{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# indicators"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import vectorbt as vbt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "Collapsed": "false"
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from datetime import datetime, timedelta\n",
    "from numba import njit\n",
    "import itertools\n",
    "import talib\n",
    "import ta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Disable caching for performance testing\n",
    "vbt.settings.caching['enabled'] = False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "close = pd.DataFrame({\n",
    "    'a': [1., 2., 3., 4., 5.],\n",
    "    'b': [5., 4., 3., 2., 1.],\n",
    "    'c': [1., 2., 3., 2., 1.]\n",
    "}, index=pd.DatetimeIndex([\n",
    "    datetime(2018, 1, 1),\n",
    "    datetime(2018, 1, 2),\n",
    "    datetime(2018, 1, 3),\n",
    "    datetime(2018, 1, 4),\n",
    "    datetime(2018, 1, 5)\n",
    "]))\n",
    "np.random.seed(42)\n",
    "high = close * np.random.uniform(1, 1.1, size=close.shape)\n",
    "low = close * np.random.uniform(0.9, 1, size=close.shape)\n",
    "volume = close * 0 + np.random.randint(1, 10, size=close.shape).astype(float)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "big_close = pd.DataFrame(np.random.randint(10, size=(1000, 1000)).astype(float))\n",
    "big_close.index = [datetime(2018, 1, 1) + timedelta(days=i) for i in range(1000)]\n",
    "big_high = big_close * np.random.uniform(1, 1.1, size=big_close.shape)\n",
    "big_low = big_close * np.random.uniform(0.9, 1, size=big_close.shape)\n",
    "big_volume = big_close * 0 + np.random.randint(10, 100, size=big_close.shape).astype(float)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "close_ts = pd.Series([1, 2, 3, 4, 3, 2, 1], index=pd.DatetimeIndex([\n",
    "    datetime(2018, 1, 1),\n",
    "    datetime(2018, 1, 2),\n",
    "    datetime(2018, 1, 3),\n",
    "    datetime(2018, 1, 4),\n",
    "    datetime(2018, 1, 5),\n",
    "    datetime(2018, 1, 6),\n",
    "    datetime(2018, 1, 7)\n",
    "]))\n",
    "high_ts = close_ts * 1.1\n",
    "low_ts = close_ts * 0.9\n",
    "volume_ts = pd.Series([4, 3, 2, 1, 2, 3, 4], index=close_ts.index)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## IndicatorFactory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p        0                    1              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  110.0  110.0  110.0  111.0  115.0  111.0\n",
      "2018-01-02  110.0  110.0  110.0  112.0  114.0  112.0\n",
      "2018-01-03  110.0  110.0  110.0  113.0  113.0  113.0\n",
      "2018-01-04  110.0  110.0  110.0  114.0  112.0  112.0\n",
      "2018-01-05  110.0  110.0  110.0  115.0  111.0  111.0\n",
      "custom_p        0                    1              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  110.0  110.0  110.0  111.0  115.0  111.0\n",
      "2018-01-02  110.0  110.0  110.0  112.0  114.0  112.0\n",
      "2018-01-03  110.0  110.0  110.0  113.0  113.0  113.0\n",
      "2018-01-04  110.0  110.0  110.0  114.0  112.0  112.0\n",
      "2018-01-05  110.0  110.0  110.0  115.0  111.0  111.0\n"
     ]
    }
   ],
   "source": [
    "def apply_func(i, ts, p, a, b=100):\n",
    "    return ts * p[i] + a + b\n",
    "\n",
    "@njit\n",
    "def apply_func_nb(i, ts, p, a, b):\n",
    "    return ts * p[i] + a + b # numba doesn't support **kwargs\n",
    "\n",
    "# Custom function can be anything that takes time series, params and other arguments, and returns outputs\n",
    "def custom_func(ts, p, *args, **kwargs):\n",
    "    return vbt.base.combine_fns.apply_and_concat_one(len(p), apply_func, ts, p, *args, **kwargs)\n",
    "\n",
    "@njit\n",
    "def custom_func_nb(ts, p, *args):\n",
    "    return vbt.base.combine_fns.apply_and_concat_one_nb(len(p), apply_func_nb, ts, p, *args)\n",
    "\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p'], output_names=['out'])\n",
    "print(F.from_custom_func(custom_func, var_args=True)\n",
    "      .run(close, [0, 1], 10, b=100).out)\n",
    "print(F.from_custom_func(custom_func_nb, var_args=True)\n",
    "      .run(close, [0, 1], 10, 100).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p        0                    1              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  110.0  110.0  110.0  111.0  115.0  111.0\n",
      "2018-01-02  110.0  110.0  110.0  112.0  114.0  112.0\n",
      "2018-01-03  110.0  110.0  110.0  113.0  113.0  113.0\n",
      "2018-01-04  110.0  110.0  110.0  114.0  112.0  112.0\n",
      "2018-01-05  110.0  110.0  110.0  115.0  111.0  111.0\n",
      "custom_p        0                    1              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  110.0  110.0  110.0  111.0  115.0  111.0\n",
      "2018-01-02  110.0  110.0  110.0  112.0  114.0  112.0\n",
      "2018-01-03  110.0  110.0  110.0  113.0  113.0  113.0\n",
      "2018-01-04  110.0  110.0  110.0  114.0  112.0  112.0\n",
      "2018-01-05  110.0  110.0  110.0  115.0  111.0  111.0\n"
     ]
    }
   ],
   "source": [
    "# Apply function is performed on each parameter individually, and each output is then stacked for you\n",
    "# Apply functions are less customizable than custom functions, but are simpler to write\n",
    "def apply_func(ts, p, a, b=100):\n",
    "    return ts * p + a + b\n",
    "\n",
    "@njit\n",
    "def apply_func_nb(ts, p, a, b):\n",
    "    return ts * p + a + b  # numba doesn't support **kwargs\n",
    "     \n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p'], output_names=['out'])\n",
    "print(F.from_apply_func(apply_func, var_args=True)\n",
    "      .run(close, [0, 1], 10, b=100).out)\n",
    "print(F.from_apply_func(apply_func_nb, var_args=True)\n",
    "      .run(close, [0, 1], 10, 100).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p      0              1               2           \n",
      "              a    b    c    a    b    c     a     b    c\n",
      "2018-01-01  3.0  3.0  3.0  4.0  8.0  4.0   5.0  13.0  5.0\n",
      "2018-01-02  3.0  3.0  3.0  5.0  7.0  5.0   7.0  11.0  7.0\n",
      "2018-01-03  3.0  3.0  3.0  6.0  6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04  3.0  3.0  3.0  7.0  5.0  5.0  11.0   7.0  7.0\n",
      "2018-01-05  3.0  3.0  3.0  8.0  4.0  4.0  13.0   5.0  5.0\n",
      "custom_p      0              1               2           \n",
      "              a    b    c    a    b    c     a     b    c\n",
      "2018-01-01  3.0  3.0  3.0  4.0  8.0  4.0   5.0  13.0  5.0\n",
      "2018-01-02  3.0  3.0  3.0  5.0  7.0  5.0   7.0  11.0  7.0\n",
      "2018-01-03  3.0  3.0  3.0  6.0  6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04  3.0  3.0  3.0  7.0  5.0  5.0  11.0   7.0  7.0\n",
      "2018-01-05  3.0  3.0  3.0  8.0  4.0  4.0  13.0   5.0  5.0\n"
     ]
    }
   ],
   "source": [
    "# test *args\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p, a: ts * p + a, var_args=True)\n",
    "      .run(close, [0, 1, 2], 3).out) \n",
    "print(F.from_apply_func(njit(lambda ts, p, a: ts * p + a), var_args=True)\n",
    "      .run(close, [0, 1, 2], 3).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p      0              1               2           \n",
      "              a    b    c    a    b    c     a     b    c\n",
      "2018-01-01  3.0  3.0  3.0  4.0  8.0  4.0   5.0  13.0  5.0\n",
      "2018-01-02  3.0  3.0  3.0  5.0  7.0  5.0   7.0  11.0  7.0\n",
      "2018-01-03  3.0  3.0  3.0  6.0  6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04  3.0  3.0  3.0  7.0  5.0  5.0  11.0   7.0  7.0\n",
      "2018-01-05  3.0  3.0  3.0  8.0  4.0  4.0  13.0   5.0  5.0\n"
     ]
    }
   ],
   "source": [
    "# test **kwargs\n",
    "# Numba doesn't support kwargs out of the box\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p, a=1: ts * p + a)\n",
    "      .run(close, [0, 1, 2], a=3).out) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p  0        1      \n",
      "          0  1  2  0  1  2\n",
      "0         0  0  0  1  1  1\n",
      "1         0  0  0  1  1  1\n",
      "2         0  0  0  1  1  1\n",
      "custom_p  0        1      \n",
      "          0  1  2  0  1  2\n",
      "0         0  0  0  1  1  1\n",
      "1         0  0  0  1  1  1\n",
      "2         0  0  0  1  1  1\n"
     ]
    }
   ],
   "source": [
    "# test no inputs\n",
    "F = vbt.IndicatorFactory(param_names=['p'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda p: np.full((3, 3), p))\n",
    "      .run([0, 1]).out)\n",
    "print(F.from_apply_func(njit(lambda p: np.full((3, 3), p)))\n",
    "      .run([0, 1]).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0    0\n",
      "1    0\n",
      "2    0\n",
      "3    0\n",
      "4    0\n",
      "dtype: int64\n",
      "0    0\n",
      "1    0\n",
      "2    0\n",
      "3    0\n",
      "4    0\n",
      "dtype: int64\n",
      "custom_p  0  1\n",
      "0         0  1\n",
      "1         0  1\n",
      "2         0  1\n",
      "3         0  1\n",
      "4         0  1\n",
      "custom_p  0  1\n",
      "0         0  1\n",
      "1         0  1\n",
      "2         0  1\n",
      "3         0  1\n",
      "4         0  1\n",
      "custom_p    0        1      \n",
      "            a  b  c  a  b  c\n",
      "2018-01-01  0  0  0  1  1  1\n",
      "2018-01-02  0  0  0  1  1  1\n",
      "2018-01-03  0  0  0  1  1  1\n",
      "2018-01-04  0  0  0  1  1  1\n",
      "2018-01-05  0  0  0  1  1  1\n",
      "custom_p    0        1      \n",
      "            a  b  c  a  b  c\n",
      "2018-01-01  0  0  0  1  1  1\n",
      "2018-01-02  0  0  0  1  1  1\n",
      "2018-01-03  0  0  0  1  1  1\n",
      "2018-01-04  0  0  0  1  1  1\n",
      "2018-01-05  0  0  0  1  1  1\n"
     ]
    }
   ],
   "source": [
    "# test no inputs with input_shape, input_index and input_columns\n",
    "F = vbt.IndicatorFactory(param_names=['p'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda input_shape, p: np.full(input_shape, p), require_input_shape=True)\n",
    "      .run((5,), 0).out)\n",
    "print(F.from_apply_func(njit(lambda input_shape, p: np.full(input_shape, p)), require_input_shape=True)\n",
    "      .run((5,), 0).out)\n",
    "\n",
    "print(F.from_apply_func(lambda input_shape, p: np.full(input_shape, p), require_input_shape=True)\n",
    "      .run((5,), [0, 1]).out)\n",
    "print(F.from_apply_func(njit(lambda input_shape, p: np.full(input_shape, p)), require_input_shape=True)\n",
    "      .run((5,), [0, 1]).out)\n",
    "\n",
    "print(F.from_apply_func(lambda input_shape, p: np.full(input_shape, p), require_input_shape=True)\n",
    "      .run((5, 3), [0, 1], input_index=close.index, input_columns=close.columns).out)\n",
    "print(F.from_apply_func(njit(lambda input_shape, p: np.full(input_shape, p)), require_input_shape=True)\n",
    "      .run((5, 3), [0, 1], input_index=close.index, input_columns=close.columns).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p      0                    1                     \n",
      "              a    b    c          a          b         c\n",
      "2018-01-01  0.0  0.0  0.0   1.037454  27.376786  1.073199\n",
      "2018-01-02  0.0  0.0  0.0   4.239463  16.249630  4.062398\n",
      "2018-01-03  0.0  0.0  0.0   9.052275   9.779559  9.541004\n",
      "2018-01-04  0.0  0.0  0.0  17.132916   4.008234  4.387964\n",
      "2018-01-05  0.0  0.0  0.0  27.081107   1.021234  1.018182\n",
      "custom_p      0                    1                     \n",
      "              a    b    c          a          b         c\n",
      "2018-01-01  0.0  0.0  0.0   1.037454  27.376786  1.073199\n",
      "2018-01-02  0.0  0.0  0.0   4.239463  16.249630  4.062398\n",
      "2018-01-03  0.0  0.0  0.0   9.052275   9.779559  9.541004\n",
      "2018-01-04  0.0  0.0  0.0  17.132916   4.008234  4.387964\n",
      "2018-01-05  0.0  0.0  0.0  27.081107   1.021234  1.018182\n"
     ]
    }
   ],
   "source": [
    "# test multiple inputs\n",
    "F = vbt.IndicatorFactory(input_names=['ts1', 'ts2'], param_names=['p'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts1, ts2, p: ts1 * ts2 * p)\n",
    "      .run(close, high, [0, 1]).out)\n",
    "print(F.from_apply_func(njit(lambda ts1, ts2, p: ts1 * ts2 * p))\n",
    "      .run(close, high, [0, 1]).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n",
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n"
     ]
    }
   ],
   "source": [
    "# test no params\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts: ts)\n",
    "      .run(close).out)\n",
    "print(F.from_apply_func(njit(lambda ts: ts))\n",
    "      .run(close).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "   0  1  2\n",
      "0  1  1  1\n",
      "1  1  1  1\n",
      "2  1  1  1\n",
      "   0  1  2\n",
      "0  1  1  1\n",
      "1  1  1  1\n",
      "2  1  1  1\n"
     ]
    }
   ],
   "source": [
    "# test no inputs and no params\n",
    "F = vbt.IndicatorFactory(output_names=['out'])\n",
    "print(F.from_apply_func(lambda: np.full((3, 3), 1))\n",
    "      .run().out)\n",
    "print(F.from_apply_func(njit(lambda: np.full((3, 3), 1)))\n",
    "      .run().out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1      0                1            \n",
      "custom_p2      2                3            \n",
      "               a     b    c     a     b     c\n",
      "2018-01-01   2.0  10.0  2.0   4.0  20.0   4.0\n",
      "2018-01-02   4.0   8.0  4.0   8.0  16.0   8.0\n",
      "2018-01-03   6.0   6.0  6.0  12.0  12.0  12.0\n",
      "2018-01-04   8.0   4.0  4.0  16.0   8.0   8.0\n",
      "2018-01-05  10.0   2.0  2.0  20.0   4.0   4.0\n",
      "custom_p1      0                1            \n",
      "custom_p2      2                3            \n",
      "               a     b    c     a     b     c\n",
      "2018-01-01   2.0  10.0  2.0   4.0  20.0   4.0\n",
      "2018-01-02   4.0   8.0  4.0   8.0  16.0   8.0\n",
      "2018-01-03   6.0   6.0  6.0  12.0  12.0  12.0\n",
      "2018-01-04   8.0   4.0  4.0  16.0   8.0   8.0\n",
      "2018-01-05  10.0   2.0  2.0  20.0   4.0   4.0\n"
     ]
    }
   ],
   "source": [
    "# test multiple params\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p1', 'p2'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2))\n",
    "      .run(close, np.asarray([0, 1]), np.asarray([2, 3])).out) \n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)))\n",
    "      .run(close, np.asarray([0, 1]), np.asarray([2, 3])).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1  array_0             array_1            \n",
      "custom_p2        2                   3            \n",
      "                 a     b     c       a     b     c\n",
      "2018-01-01     2.0  15.0   4.0     3.0  20.0   5.0\n",
      "2018-01-02     4.0  12.0   8.0     6.0  16.0  10.0\n",
      "2018-01-03     6.0   9.0  12.0     9.0  12.0  15.0\n",
      "2018-01-04     8.0   6.0   8.0    12.0   8.0  10.0\n",
      "2018-01-05    10.0   3.0   4.0    15.0   4.0   5.0\n",
      "custom_p1  array_0             array_1            \n",
      "custom_p2        2                   3            \n",
      "                 a     b     c       a     b     c\n",
      "2018-01-01     2.0  15.0   4.0     3.0  20.0   5.0\n",
      "2018-01-02     4.0  12.0   8.0     6.0  16.0  10.0\n",
      "2018-01-03     6.0   9.0  12.0     9.0  12.0  15.0\n",
      "2018-01-04     8.0   6.0   8.0    12.0   8.0  10.0\n",
      "2018-01-05    10.0   3.0   4.0    15.0   4.0   5.0\n"
     ]
    }
   ],
   "source": [
    "# test param_settings array_like\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p1', 'p2'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2), \n",
    "                        param_settings={'p1': {'is_array_like': True}})\n",
    "      .run(close, np.asarray([0, 1, 2]), np.asarray([2, 3])).out) \n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)), \n",
    "                        param_settings={'p1': {'is_array_like': True}})\n",
    "      .run(close, np.asarray([0, 1, 2]), np.asarray([2, 3])).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1  array_0             array_1            \n",
      "custom_p2        2                   3            \n",
      "                 a     b     c       a     b     c\n",
      "2018-01-01     2.0  15.0   4.0     3.0  20.0   5.0\n",
      "2018-01-02     4.0  12.0   8.0     6.0  16.0  10.0\n",
      "2018-01-03     6.0   9.0  12.0     9.0  12.0  15.0\n",
      "2018-01-04     8.0   6.0   8.0    12.0   8.0  10.0\n",
      "2018-01-05    10.0   3.0   4.0    15.0   4.0   5.0\n",
      "custom_p1  array_0             array_1            \n",
      "custom_p2        2                   3            \n",
      "                 a     b     c       a     b     c\n",
      "2018-01-01     2.0  15.0   4.0     3.0  20.0   5.0\n",
      "2018-01-02     4.0  12.0   8.0     6.0  16.0  10.0\n",
      "2018-01-03     6.0   9.0  12.0     9.0  12.0  15.0\n",
      "2018-01-04     8.0   6.0   8.0    12.0   8.0  10.0\n",
      "2018-01-05    10.0   3.0   4.0    15.0   4.0   5.0\n"
     ]
    }
   ],
   "source": [
    "# test param_settings bc_to_input\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p1', 'p2'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2), \n",
    "                        param_settings={'p1': {'is_array_like': True, 'bc_to_input': True}})\n",
    "      .run(close, np.asarray([0, 1, 2]), np.asarray([2, 3])).out) \n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)), \n",
    "                        param_settings={'p1': {'is_array_like': True, 'bc_to_input': True}})\n",
    "      .run(close, np.asarray([0, 1, 2]), np.asarray([2, 3])).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1      0                                 1                         \\\n",
      "custom_p2      2                3                2                3         \n",
      "               a     b    c     a     b    c     a     b    c     a     b   \n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0   3.0  15.0  3.0   4.0  20.0   \n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0   6.0  12.0  6.0   8.0  16.0   \n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0   9.0   9.0  9.0  12.0  12.0   \n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0  12.0   6.0  6.0  16.0   8.0   \n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0  15.0   3.0  3.0  20.0   4.0   \n",
      "\n",
      "custom_p1         \n",
      "custom_p2         \n",
      "               c  \n",
      "2018-01-01   4.0  \n",
      "2018-01-02   8.0  \n",
      "2018-01-03  12.0  \n",
      "2018-01-04   8.0  \n",
      "2018-01-05   4.0  \n",
      "custom_p1      0                                 1                         \\\n",
      "custom_p2      2                3                2                3         \n",
      "               a     b    c     a     b    c     a     b    c     a     b   \n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0   3.0  15.0  3.0   4.0  20.0   \n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0   6.0  12.0  6.0   8.0  16.0   \n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0   9.0   9.0  9.0  12.0  12.0   \n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0  12.0   6.0  6.0  16.0   8.0   \n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0  15.0   3.0  3.0  20.0   4.0   \n",
      "\n",
      "custom_p1         \n",
      "custom_p2         \n",
      "               c  \n",
      "2018-01-01   4.0  \n",
      "2018-01-02   8.0  \n",
      "2018-01-03  12.0  \n",
      "2018-01-04   8.0  \n",
      "2018-01-05   4.0  \n"
     ]
    }
   ],
   "source": [
    "# test param product\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p1', 'p2'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2))\n",
    "      .run(close, [0, 1], [2, 3], param_product=True).out) \n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)))\n",
    "      .run(close, [0, 1], [2, 3], param_product=True).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1      0                1           \n",
      "               a     b    c     a     b    c\n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0\n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0\n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0\n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0\n",
      "custom_p1      0                1           \n",
      "               a     b    c     a     b    c\n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0\n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0\n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0\n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0\n"
     ]
    }
   ],
   "source": [
    "# test default params\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p1', 'p2'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2), p2=2)\n",
    "      .run(close, [0, 1]).out)\n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)), p2=2)\n",
    "      .run(close, [0, 1]).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1      0                1           \n",
      "               a     b    c     a     b    c\n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0\n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0\n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0\n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0\n",
      "custom_p1      0                1           \n",
      "               a     b    c     a     b    c\n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0\n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0\n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0\n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0\n"
     ]
    }
   ],
   "source": [
    "# test hide_params\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p1', 'p2'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2), hide_params=['p2'])\n",
    "      .run(close, [0, 1], 2).out)\n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)), hide_params=['p2'])\n",
    "      .run(close, [0, 1], 2).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1      0                1           \n",
      "custom_p2      2                2           \n",
      "               a     b    c     a     b    c\n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0\n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0\n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0\n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0\n",
      "custom_p1      0                1           \n",
      "custom_p2      2                2           \n",
      "               a     b    c     a     b    c\n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0\n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0\n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0\n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0\n",
      "custom_p1      0                1           \n",
      "               a     b    c     a     b    c\n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0\n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0\n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0\n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0\n",
      "custom_p1      0                1           \n",
      "               a     b    c     a     b    c\n",
      "2018-01-01   2.0  10.0  2.0   3.0  15.0  3.0\n",
      "2018-01-02   4.0   8.0  4.0   6.0  12.0  6.0\n",
      "2018-01-03   6.0   6.0  6.0   9.0   9.0  9.0\n",
      "2018-01-04   8.0   4.0  4.0  12.0   6.0  6.0\n",
      "2018-01-05  10.0   2.0  2.0  15.0   3.0  3.0\n"
     ]
    }
   ],
   "source": [
    "# test hide_default\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p1', 'p2'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2), p2=2)\n",
    "      .run(close, [0, 1], hide_default=False).out)\n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)), p2=2)\n",
    "      .run(close, [0, 1], hide_default=False).out)\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2), p2=2)\n",
    "      .run(close, [0, 1], hide_default=True).out)\n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)), p2=2)\n",
    "      .run(close, [0, 1], hide_default=True).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p      0              1          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  0.0  0.0  0.0  1.0  5.0  1.0\n",
      "2018-01-02  0.0  0.0  0.0  2.0  4.0  2.0\n",
      "2018-01-03  0.0  0.0  0.0  3.0  3.0  3.0\n",
      "2018-01-04  0.0  0.0  0.0  4.0  2.0  2.0\n",
      "2018-01-05  0.0  0.0  0.0  5.0  1.0  1.0\n",
      "custom_p      0              1          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  0.0  0.0  0.0  1.0  5.0  1.0\n",
      "2018-01-02  0.0  0.0  0.0  2.0  4.0  2.0\n",
      "2018-01-03  0.0  0.0  0.0  3.0  3.0  3.0\n",
      "2018-01-04  0.0  0.0  0.0  4.0  2.0  2.0\n",
      "2018-01-05  0.0  0.0  0.0  5.0  1.0  1.0\n",
      "custom_p      0              1          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  0.0  0.0  0.0  1.0  5.0  1.0\n",
      "2018-01-02  0.0  0.0  0.0  2.0  4.0  2.0\n",
      "2018-01-03  0.0  0.0  0.0  3.0  3.0  3.0\n",
      "2018-01-04  0.0  0.0  0.0  4.0  2.0  2.0\n",
      "2018-01-05  0.0  0.0  0.0  5.0  1.0  1.0\n",
      "custom_p      0              1          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  0.0  0.0  0.0  1.0  5.0  1.0\n",
      "2018-01-02  0.0  0.0  0.0  2.0  4.0  2.0\n",
      "2018-01-03  0.0  0.0  0.0  3.0  3.0  3.0\n",
      "2018-01-04  0.0  0.0  0.0  4.0  2.0  2.0\n",
      "2018-01-05  0.0  0.0  0.0  5.0  1.0  1.0\n"
     ]
    }
   ],
   "source": [
    "# test multiple outputs\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p'], output_names=['o1', 'o2'])\n",
    "print(F.from_apply_func(lambda ts, p: (ts * p, ts * p ** 2))\n",
    "      .run(close, [0, 1]).o1)\n",
    "print(F.from_apply_func(lambda ts, p: (ts * p, ts * p ** 2))\n",
    "      .run(close, [0, 1]).o2)\n",
    "print(F.from_apply_func(njit(lambda ts, p: (ts * p, ts * p ** 2)))\n",
    "      .run(close, [0, 1]).o1)\n",
    "print(F.from_apply_func(njit(lambda ts, p: (ts * p, ts * p ** 2)))\n",
    "      .run(close, [0, 1]).o2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p      0              1          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  0.0  0.0  0.0  1.0  0.0  0.0\n",
      "2018-01-02  0.0  0.0  0.0  1.0  0.0  0.0\n",
      "2018-01-03  0.0  0.0  0.0  1.0  2.0  3.0\n",
      "2018-01-04  0.0  5.0  5.0  1.0  3.0  2.0\n",
      "2018-01-05  0.0  1.0  2.0  1.0  2.0  1.0\n",
      "custom_p      0              1          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  0.0  0.0  0.0  1.0  0.0  0.0\n",
      "2018-01-02  0.0  0.0  0.0  1.0  0.0  0.0\n",
      "2018-01-03  0.0  0.0  0.0  1.0  2.0  3.0\n",
      "2018-01-04  0.0  5.0  5.0  1.0  3.0  2.0\n",
      "2018-01-05  0.0  1.0  2.0  1.0  2.0  1.0\n",
      "custom_p    0                                            1  \\\n",
      "            a                    b                    c  a   \n",
      "2018-01-01  0                    0                    0  1   \n",
      "2018-01-02  0                    0                    0  1   \n",
      "2018-01-03  0                    0                    0  1   \n",
      "2018-01-04  0  4617315517961601024  4617315517961601024  1   \n",
      "2018-01-05  0  4607182418800017408  4611686018427387904  1   \n",
      "\n",
      "custom_p                                              \n",
      "                              b                    c  \n",
      "2018-01-01                    0                    0  \n",
      "2018-01-02                    0                    0  \n",
      "2018-01-03  4611686018427387904  4613937818241073152  \n",
      "2018-01-04  4613937818241073152  4611686018427387904  \n",
      "2018-01-05  4611686018427387904  4607182418800017408  \n",
      "custom_p    0                                            1  \\\n",
      "            a                    b                    c  a   \n",
      "2018-01-01  0  4616189618054758400  4618441417868443648  1   \n",
      "2018-01-02  0  4618441417868443648  4616189618054758400  1   \n",
      "2018-01-03  0  4616189618054758400  4611686018427387904  1   \n",
      "2018-01-04  0  4624633867356078080  4624633867356078080  1   \n",
      "2018-01-05  0  4613937818241073152  4618441417868443648  1   \n",
      "\n",
      "custom_p                                              \n",
      "                              b                    c  \n",
      "2018-01-01  4621819117588971520  4621819117588971520  \n",
      "2018-01-02  4611686018427387904  4616189618054758400  \n",
      "2018-01-03  4618441417868443648  4621256167635550208  \n",
      "2018-01-04  4621256167635550208  4618441417868443648  \n",
      "2018-01-05  4618441417868443648  4613937818241073152  \n",
      "custom_p    0        1      \n",
      "            a  b  c  a  b  c\n",
      "2018-01-01  0 -1 -1  1 -1 -1\n",
      "2018-01-02  0 -1 -1  1 -1 -1\n",
      "2018-01-03  0 -1 -1  1 -1 -1\n",
      "2018-01-04  0 -1 -1  1 -1 -1\n",
      "2018-01-05  0 -1 -1  1 -1 -1\n",
      "custom_p    0        1      \n",
      "            a  b  c  a  b  c\n",
      "2018-01-01  0 -1 -1  1 -1 -1\n",
      "2018-01-02  0 -1 -1  1 -1 -1\n",
      "2018-01-03  0 -1 -1  1 -1 -1\n",
      "2018-01-04  0 -1 -1  1 -1 -1\n",
      "2018-01-05  0 -1 -1  1 -1 -1\n"
     ]
    }
   ],
   "source": [
    "# test in-place outputs\n",
    "def apply_func(ts, ts_out, p):\n",
    "    ts_out[:, 0] = p\n",
    "    return ts * p\n",
    "\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p'], output_names=['out'], in_output_names=['ts_out'])\n",
    "print(F.from_apply_func(apply_func)\n",
    "      .run(close, [0, 1]).ts_out)\n",
    "print(F.from_apply_func(njit(apply_func))\n",
    "      .run(close, [0, 1]).ts_out)\n",
    "\n",
    "print(F.from_apply_func(apply_func, in_output_settings={'ts_out': {'dtype': np.int64}})\n",
    "      .run(close, [0, 1]).ts_out)\n",
    "print(F.from_apply_func(njit(apply_func), in_output_settings={'ts_out': {'dtype': np.int64}})\n",
    "      .run(close, [0, 1]).ts_out)\n",
    "\n",
    "print(F.from_apply_func(apply_func, ts_out=-1)\n",
    "      .run(close, [0, 1]).ts_out)\n",
    "print(F.from_apply_func(njit(apply_func), ts_out=-1)\n",
    "      .run(close, [0, 1]).ts_out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p       0                 1                 2            \n",
      "               a     b     c     a     b     c     a     b     c\n",
      "2018-01-01  13.0  13.0  13.0  14.0  18.0  14.0  15.0  23.0  15.0\n",
      "2018-01-02  13.0  13.0  13.0  15.0  17.0  15.0  17.0  21.0  17.0\n",
      "2018-01-03  13.0  13.0  13.0  16.0  16.0  16.0  19.0  19.0  19.0\n",
      "2018-01-04  13.0  13.0  13.0  17.0  15.0  15.0  21.0  17.0  17.0\n",
      "2018-01-05  13.0  13.0  13.0  18.0  14.0  14.0  23.0  15.0  15.0\n",
      "custom_p       0                 1                 2            \n",
      "               a     b     c     a     b     c     a     b     c\n",
      "2018-01-01  13.0  13.0  13.0  14.0  18.0  14.0  15.0  23.0  15.0\n",
      "2018-01-02  13.0  13.0  13.0  15.0  17.0  15.0  17.0  21.0  17.0\n",
      "2018-01-03  13.0  13.0  13.0  16.0  16.0  16.0  19.0  19.0  19.0\n",
      "2018-01-04  13.0  13.0  13.0  17.0  15.0  15.0  21.0  17.0  17.0\n",
      "2018-01-05  13.0  13.0  13.0  18.0  14.0  14.0  23.0  15.0  15.0\n"
     ]
    }
   ],
   "source": [
    "# test kwargs_to_args\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p, a, kw: ts * p + a + kw, kwargs_to_args=['kw'], var_args=True)\n",
    "      .run(close, [0, 1, 2], 3, kw=10).out) \n",
    "print(F.from_apply_func(njit(lambda ts, p, a, kw: ts * p + a + kw), kwargs_to_args=['kw'], var_args=True)\n",
    "      .run(close, [0, 1, 2], 3, kw=10).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p        0                    1              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  100.0  100.0  100.0  101.0  105.0  101.0\n",
      "2018-01-02  100.0  100.0  100.0  102.0  104.0  102.0\n",
      "2018-01-03  100.0  100.0  100.0  103.0  103.0  103.0\n",
      "2018-01-04  100.0  100.0  100.0  104.0  102.0  102.0\n",
      "2018-01-05  100.0  100.0  100.0  105.0  101.0  101.0\n",
      "custom_p        0                    1              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  100.0  100.0  100.0  101.0  105.0  101.0\n",
      "2018-01-02  100.0  100.0  100.0  102.0  104.0  102.0\n",
      "2018-01-03  100.0  100.0  100.0  103.0  103.0  103.0\n",
      "2018-01-04  100.0  100.0  100.0  104.0  102.0  102.0\n",
      "2018-01-05  100.0  100.0  100.0  105.0  101.0  101.0\n"
     ]
    }
   ],
   "source": [
    "# test caching func\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, param, c: ts * param + c, cache_func=lambda ts, params: 100)\n",
    "      .run(close, [0, 1]).out)\n",
    "print(F.from_apply_func(njit(lambda ts, param, c: ts * param + c), cache_func=njit(lambda ts, params: 100))\n",
    "      .run(close, [0, 1]).out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "i1_p1          0                                 1            \n",
      "i1_p2          3                                 4            \n",
      "               a     b    c     a     b    c     a     b     c\n",
      "2018-01-01   3.0  15.0  3.0   3.0  15.0  3.0   5.0  25.0   5.0\n",
      "2018-01-02   6.0  12.0  6.0   6.0  12.0  6.0  10.0  20.0  10.0\n",
      "2018-01-03   9.0   9.0  9.0   9.0   9.0  9.0  15.0  15.0  15.0\n",
      "2018-01-04  12.0   6.0  6.0  12.0   6.0  6.0  20.0  10.0  10.0\n",
      "2018-01-05  15.0   3.0  3.0  15.0   3.0  3.0  25.0   5.0   5.0\n",
      "i2_p1          1                 2                              \n",
      "i2_p2          4                 5                              \n",
      "               a     b     c     a     b     c     a     b     c\n",
      "2018-01-01   5.0  25.0   5.0   7.0  35.0   7.0   7.0  35.0   7.0\n",
      "2018-01-02  10.0  20.0  10.0  14.0  28.0  14.0  14.0  28.0  14.0\n",
      "2018-01-03  15.0  15.0  15.0  21.0  21.0  21.0  21.0  21.0  21.0\n",
      "2018-01-04  20.0  10.0  10.0  28.0  14.0  14.0  28.0  14.0  14.0\n",
      "2018-01-05  25.0   5.0   5.0  35.0   7.0   7.0  35.0   7.0   7.0\n",
      "i1_p1          0                                 1            \n",
      "i1_p2          3                                 4            \n",
      "               a     b    c     a     b    c     a     b     c\n",
      "2018-01-01   3.0  15.0  3.0   3.0  15.0  3.0   5.0  25.0   5.0\n",
      "2018-01-02   6.0  12.0  6.0   6.0  12.0  6.0  10.0  20.0  10.0\n",
      "2018-01-03   9.0   9.0  9.0   9.0   9.0  9.0  15.0  15.0  15.0\n",
      "2018-01-04  12.0   6.0  6.0  12.0   6.0  6.0  20.0  10.0  10.0\n",
      "2018-01-05  15.0   3.0  3.0  15.0   3.0  3.0  25.0   5.0   5.0\n",
      "i2_p1          1                 2                              \n",
      "i2_p2          4                 5                              \n",
      "               a     b     c     a     b     c     a     b     c\n",
      "2018-01-01   5.0  25.0   5.0   7.0  35.0   7.0   7.0  35.0   7.0\n",
      "2018-01-02  10.0  20.0  10.0  14.0  28.0  14.0  14.0  28.0  14.0\n",
      "2018-01-03  15.0  15.0  15.0  21.0  21.0  21.0  21.0  21.0  21.0\n",
      "2018-01-04  20.0  10.0  10.0  28.0  14.0  14.0  28.0  14.0  14.0\n",
      "2018-01-05  25.0   5.0   5.0  35.0   7.0   7.0  35.0   7.0   7.0\n"
     ]
    }
   ],
   "source": [
    "# test run_combs\n",
    "F = vbt.IndicatorFactory(input_names=['ts'], param_names=['p1', 'p2'], output_names=['out'])\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2))\n",
    "      .run_combs(close, [0, 1, 2], [3, 4, 5], short_names=['i1', 'i2'])[0].out)\n",
    "print(F.from_apply_func(lambda ts, p1, p2: ts * (p1 + p2))\n",
    "      .run_combs(close, [0, 1, 2], [3, 4, 5], short_names=['i1', 'i2'])[1].out)\n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)))\n",
    "      .run_combs(close, [0, 1, 2], [3, 4, 5], short_names=['i1', 'i2'])[0].out)\n",
    "print(F.from_apply_func(njit(lambda ts, p1, p2: ts * (p1 + p2)))\n",
    "      .run_combs(close, [0, 1, 2], [3, 4, 5], short_names=['i1', 'i2'])[1].out)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__annotations__',\n",
       " '__class__',\n",
       " '__delattr__',\n",
       " '__dict__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__getitem__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__init_subclass__',\n",
       " '__le__',\n",
       " '__lt__',\n",
       " '__module__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " '__weakref__',\n",
       " '_config',\n",
       " '_iloc',\n",
       " '_in_output_names',\n",
       " '_indexing_kwargs',\n",
       " '_input_mapper',\n",
       " '_input_names',\n",
       " '_level_names',\n",
       " '_loc',\n",
       " '_metrics',\n",
       " '_o1',\n",
       " '_o2',\n",
       " '_output_flags',\n",
       " '_output_names',\n",
       " '_param_names',\n",
       " '_run',\n",
       " '_run_combs',\n",
       " '_short_name',\n",
       " '_ts',\n",
       " '_ts_out',\n",
       " '_wrapper',\n",
       " 'apply_func',\n",
       " 'build_metrics_doc',\n",
       " 'config',\n",
       " 'copy',\n",
       " 'custom_func',\n",
       " 'deep_getattr',\n",
       " 'dumps',\n",
       " 'iloc',\n",
       " 'in_output_names',\n",
       " 'indexing_func',\n",
       " 'indexing_kwargs',\n",
       " 'input_names',\n",
       " 'level_names',\n",
       " 'load',\n",
       " 'loads',\n",
       " 'loc',\n",
       " 'metrics',\n",
       " 'o1',\n",
       " 'o1_above',\n",
       " 'o1_below',\n",
       " 'o1_equal',\n",
       " 'o1_stats',\n",
       " 'o2',\n",
       " 'o2_and',\n",
       " 'o2_or',\n",
       " 'o2_stats',\n",
       " 'o2_xor',\n",
       " 'output_flags',\n",
       " 'output_names',\n",
       " 'override_metrics_doc',\n",
       " 'param_names',\n",
       " 'post_resolve_attr',\n",
       " 'pre_resolve_attr',\n",
       " 'regroup',\n",
       " 'resolve_attr',\n",
       " 'resolve_self',\n",
       " 'run',\n",
       " 'run_combs',\n",
       " 'save',\n",
       " 'select_one',\n",
       " 'select_one_from_obj',\n",
       " 'self_aliases',\n",
       " 'short_name',\n",
       " 'stats',\n",
       " 'stats_defaults',\n",
       " 'to_doc',\n",
       " 'ts',\n",
       " 'ts_above',\n",
       " 'ts_below',\n",
       " 'ts_equal',\n",
       " 'ts_out',\n",
       " 'ts_out_readable',\n",
       " 'ts_out_stats',\n",
       " 'ts_stats',\n",
       " 'update_config',\n",
       " 'wrapper',\n",
       " 'writeable_attrs',\n",
       " 'xs']"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import namedtuple\n",
    "\n",
    "TestEnum = namedtuple('TestEnum', ['Hello', 'World'])(0, 1)\n",
    "# test attr_settings\n",
    "F = vbt.IndicatorFactory(\n",
    "    input_names=['ts'], output_names=['o1', 'o2'], in_output_names=['ts_out'],\n",
    "    attr_settings={\n",
    "        'ts': {'dtype': None}, \n",
    "        'o1': {'dtype': np.float64}, \n",
    "        'o2': {'dtype': np.bool_}, \n",
    "        'ts_out': {'dtype': TestEnum}\n",
    "    }\n",
    ")\n",
    "dir(F.from_apply_func(lambda ts, ts_out: (ts + ts_out, ts + ts_out)).run(close))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "CustomInd = vbt.IndicatorFactory(\n",
    "    input_names=['ts1', 'ts2'],\n",
    "    param_names=['p1', 'p2'],\n",
    "    output_names=['o1', 'o2']\n",
    ").from_apply_func(lambda ts1, ts2, p1, p2: (ts1 * p1, ts2 * p2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__annotations__',\n",
       " '__class__',\n",
       " '__delattr__',\n",
       " '__dict__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__getitem__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__init_subclass__',\n",
       " '__le__',\n",
       " '__lt__',\n",
       " '__module__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " '__weakref__',\n",
       " '_in_output_names',\n",
       " '_input_names',\n",
       " '_metrics',\n",
       " '_output_flags',\n",
       " '_output_names',\n",
       " '_param_names',\n",
       " '_run',\n",
       " '_run_combs',\n",
       " 'apply_func',\n",
       " 'build_metrics_doc',\n",
       " 'config',\n",
       " 'copy',\n",
       " 'custom_func',\n",
       " 'deep_getattr',\n",
       " 'dumps',\n",
       " 'iloc',\n",
       " 'in_output_names',\n",
       " 'indexing_func',\n",
       " 'indexing_kwargs',\n",
       " 'input_names',\n",
       " 'level_names',\n",
       " 'load',\n",
       " 'loads',\n",
       " 'loc',\n",
       " 'metrics',\n",
       " 'o1',\n",
       " 'o1_above',\n",
       " 'o1_below',\n",
       " 'o1_equal',\n",
       " 'o1_stats',\n",
       " 'o2',\n",
       " 'o2_above',\n",
       " 'o2_below',\n",
       " 'o2_equal',\n",
       " 'o2_stats',\n",
       " 'output_flags',\n",
       " 'output_names',\n",
       " 'override_metrics_doc',\n",
       " 'p1_list',\n",
       " 'p1_loc',\n",
       " 'p2_list',\n",
       " 'p2_loc',\n",
       " 'param_names',\n",
       " 'post_resolve_attr',\n",
       " 'pre_resolve_attr',\n",
       " 'regroup',\n",
       " 'resolve_attr',\n",
       " 'resolve_self',\n",
       " 'run',\n",
       " 'run_combs',\n",
       " 'save',\n",
       " 'select_one',\n",
       " 'select_one_from_obj',\n",
       " 'self_aliases',\n",
       " 'short_name',\n",
       " 'stats',\n",
       " 'stats_defaults',\n",
       " 'to_doc',\n",
       " 'ts1',\n",
       " 'ts1_above',\n",
       " 'ts1_below',\n",
       " 'ts1_equal',\n",
       " 'ts1_stats',\n",
       " 'ts2',\n",
       " 'ts2_above',\n",
       " 'ts2_below',\n",
       " 'ts2_equal',\n",
       " 'ts2_stats',\n",
       " 'tuple_loc',\n",
       " 'update_config',\n",
       " 'wrapper',\n",
       " 'writeable_attrs',\n",
       " 'xs']"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dir(CustomInd) # you can list here all of the available tools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "custom_ind = CustomInd.run(close, high, [1, 2], [3, 4])\n",
    "big_custom_ind = CustomInd.run(big_close, big_high, [1, 2], [3, 4])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',\n",
      "               '2018-01-05'],\n",
      "              dtype='datetime64[ns]', freq=None)\n",
      "MultiIndex([(1, 3, 'a'),\n",
      "            (1, 3, 'b'),\n",
      "            (1, 3, 'c'),\n",
      "            (2, 4, 'a'),\n",
      "            (2, 4, 'b'),\n",
      "            (2, 4, 'c')],\n",
      "           names=['custom_p1', 'custom_p2', None])\n",
      "2\n",
      "(5, 6)\n",
      "1 days 00:00:00\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind.wrapper.index) # subclasses ArrayWrapper\n",
    "print(custom_ind.wrapper.columns)\n",
    "print(custom_ind.wrapper.ndim)\n",
    "print(custom_ind.wrapper.shape)\n",
    "print(custom_ind.wrapper.freq)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom\n",
      "('custom_p1', 'custom_p2')\n",
      "('ts1', 'ts2')\n",
      "('p1', 'p2')\n",
      "('o1', 'o2')\n",
      "{}\n",
      "[1, 2]\n",
      "[3, 4]\n"
     ]
    }
   ],
   "source": [
    "# not changed during indexing\n",
    "print(custom_ind.short_name)\n",
    "print(custom_ind.level_names)\n",
    "print(custom_ind.input_names)\n",
    "print(custom_ind.param_names)\n",
    "print(custom_ind.output_names)\n",
    "print(custom_ind.output_flags)\n",
    "print(custom_ind.p1_list)\n",
    "print(custom_ind.p2_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pandas indexing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1. 5. 1.]\n",
      " [2. 4. 2.]\n",
      " [3. 3. 3.]\n",
      " [4. 2. 2.]\n",
      " [5. 1. 1.]]\n",
      "custom_p1     1              2          \n",
      "custom_p2     3              4          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  1.0  5.0  1.0  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0  5.0  1.0  1.0\n",
      "2018-01-01    1.0\n",
      "2018-01-02    2.0\n",
      "2018-01-03    3.0\n",
      "2018-01-04    4.0\n",
      "2018-01-05    5.0\n",
      "Name: (1, 3, a), dtype: float64\n",
      "2018-01-01    1.0\n",
      "2018-01-02    2.0\n",
      "2018-01-03    3.0\n",
      "2018-01-04    4.0\n",
      "2018-01-05    5.0\n",
      "Name: (1, 3, a), dtype: float64\n",
      "custom_p1     1\n",
      "custom_p2     3\n",
      "              a\n",
      "2018-01-01  1.0\n",
      "2018-01-02  2.0\n",
      "2018-01-03  3.0\n",
      "2018-01-04  4.0\n",
      "2018-01-05  5.0\n",
      "custom_p1     1\n",
      "custom_p2     3\n",
      "              a\n",
      "2018-01-01  1.0\n",
      "2018-01-02  2.0\n",
      "2018-01-03  3.0\n",
      "2018-01-04  4.0\n",
      "2018-01-05  5.0\n",
      "custom_p1     1              2          \n",
      "custom_p2     3              4          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  1.0  5.0  1.0  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0  2.0  4.0  2.0\n",
      "custom_p1     1              2          \n",
      "custom_p2     3              4          \n",
      "              a    b    c    a    b    c\n",
      "2018-01-01  1.0  5.0  1.0  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0  2.0  4.0  2.0\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind._ts1)\n",
    "print(custom_ind.ts1)\n",
    "\n",
    "print(custom_ind.ts1.iloc[:, 0])\n",
    "print(custom_ind.iloc[:, 0].ts1)\n",
    "\n",
    "print(custom_ind.ts1.iloc[:, [0]])\n",
    "print(custom_ind.iloc[:, [0]].ts1)\n",
    "\n",
    "print(custom_ind.ts1.iloc[:2, :])\n",
    "print(custom_ind.iloc[:2, :].ts1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01    1.0\n",
      "2018-01-02    2.0\n",
      "2018-01-03    3.0\n",
      "2018-01-04    4.0\n",
      "2018-01-05    5.0\n",
      "Name: (1, 3, a), dtype: float64\n",
      "120 µs ± 540 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "2018-01-01    1.0\n",
      "2018-01-02    2.0\n",
      "2018-01-03    3.0\n",
      "2018-01-04    4.0\n",
      "2018-01-05    5.0\n",
      "Name: (1, 3, a), dtype: float64\n",
      "1.33 ms ± 40.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind.o1.iloc[:, 0])\n",
    "%timeit big_custom_ind.o1.iloc[:, 0] # benchmark, 1 column\n",
    "\n",
    "print(custom_ind.iloc[:, 0].o1) # performed on the object itself\n",
    "%timeit big_custom_ind.iloc[:, 0] # slower since it forwards the operation to each dataframe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1     1          \n",
      "custom_p2     3          \n",
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n",
      "910 µs ± 59.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "custom_p1     1          \n",
      "custom_p2     3          \n",
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n",
      "18 ms ± 759 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind.o1.iloc[:, np.arange(3)])\n",
    "%timeit big_custom_ind.o1.iloc[:, np.arange(1000)] # 1000 columns\n",
    "\n",
    "print(custom_ind.iloc[:, np.arange(3)].o1)\n",
    "%timeit big_custom_ind.iloc[:, np.arange(1000)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01    1.0\n",
      "2018-01-02    2.0\n",
      "2018-01-03    3.0\n",
      "2018-01-04    4.0\n",
      "2018-01-05    5.0\n",
      "Name: (1, 3, a), dtype: float64\n",
      "147 µs ± 270 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "2018-01-01    1.0\n",
      "2018-01-02    2.0\n",
      "2018-01-03    3.0\n",
      "2018-01-04    4.0\n",
      "2018-01-05    5.0\n",
      "Name: (1, 3, a), dtype: float64\n",
      "1.34 ms ± 4.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind.o1.loc[:, (1, 3, 'a')])\n",
    "%timeit big_custom_ind.o1.loc[:, (1, 3, 0)] # 1 column\n",
    "\n",
    "print(custom_ind.loc[:, (1, 3, 'a')].o1)\n",
    "%timeit big_custom_ind.loc[:, (1, 3, 0)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n",
      "169 µs ± 1.54 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n",
      "6.1 ms ± 75.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind.o1.loc[:, (1, 3)])\n",
    "%timeit big_custom_ind.o1.loc[:, 1] # 1000 columns\n",
    "\n",
    "print(custom_ind.loc[:, (1, 3)].o1)\n",
    "%timeit big_custom_ind.loc[:, 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p2     3          \n",
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n",
      "161 µs ± 371 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n",
      "custom_p2     3          \n",
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n",
      "6.2 ms ± 119 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind.o1.xs(1, axis=1, level=0))\n",
    "%timeit big_custom_ind.o1.xs(1, axis=1, level=0) # 1000 columns\n",
    "\n",
    "print(custom_ind.xs(1, axis=1, level=0).o1)\n",
    "%timeit big_custom_ind.xs(1, axis=1, level=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Parameter indexing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Index([1, 1, 1, 2, 2, 2], dtype='int64', name='custom_p1')\n",
      "custom_p2      4           \n",
      "               a     b    c\n",
      "2018-01-01   2.0  10.0  2.0\n",
      "2018-01-02   4.0   8.0  4.0\n",
      "2018-01-03   6.0   6.0  6.0\n",
      "2018-01-04   8.0   4.0  4.0\n",
      "2018-01-05  10.0   2.0  2.0\n",
      "custom_p1     1               2           \n",
      "custom_p2     3               4           \n",
      "              a    b    c     a     b    c\n",
      "2018-01-01  1.0  5.0  1.0   2.0  10.0  2.0\n",
      "2018-01-02  2.0  4.0  2.0   4.0   8.0  4.0\n",
      "2018-01-03  3.0  3.0  3.0   6.0   6.0  6.0\n",
      "2018-01-04  4.0  2.0  2.0   8.0   4.0  4.0\n",
      "2018-01-05  5.0  1.0  1.0  10.0   2.0  2.0\n",
      "custom_p1     1                                        \n",
      "custom_p2     3                                        \n",
      "              a    b    c    a    b    c    a    b    c\n",
      "2018-01-01  1.0  5.0  1.0  1.0  5.0  1.0  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0  2.0  4.0  2.0  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0  3.0  3.0  3.0  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0  4.0  2.0  2.0  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0  5.0  1.0  1.0  5.0  1.0  1.0\n"
     ]
    }
   ],
   "source": [
    "# Indexing by parameter\n",
    "print(custom_ind._p1_mapper)\n",
    "print(custom_ind.p1_loc[2].o1)\n",
    "print(custom_ind.p1_loc[1:2].o1)\n",
    "print(custom_ind.p1_loc[[1, 1, 1]].o1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "18.2 ms ± 1.45 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "122 ms ± 18.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit big_custom_ind.p1_loc[1] # 1000 columns\n",
    "%timeit big_custom_ind.p1_loc[np.full(10, 1)] # 10000 columns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(1, 3), (1, 3), (1, 3), (2, 4), (2, 4), (2, 4)]\n",
      "              a    b    c\n",
      "2018-01-01  1.0  5.0  1.0\n",
      "2018-01-02  2.0  4.0  2.0\n",
      "2018-01-03  3.0  3.0  3.0\n",
      "2018-01-04  4.0  2.0  2.0\n",
      "2018-01-05  5.0  1.0  1.0\n",
      "custom_p1     1               2           \n",
      "custom_p2     3               4           \n",
      "              a    b    c     a     b    c\n",
      "2018-01-01  1.0  5.0  1.0   2.0  10.0  2.0\n",
      "2018-01-02  2.0  4.0  2.0   4.0   8.0  4.0\n",
      "2018-01-03  3.0  3.0  3.0   6.0   6.0  6.0\n",
      "2018-01-04  4.0  2.0  2.0   8.0   4.0  4.0\n",
      "2018-01-05  5.0  1.0  1.0  10.0   2.0  2.0\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind._tuple_mapper)\n",
    "print(custom_ind.tuple_loc[(1, 3)].o1)\n",
    "print(custom_ind.tuple_loc[(1, 3):(2, 4)].o1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "22.5 ms ± 5.03 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "172 ms ± 10.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit big_custom_ind.tuple_loc[(1, 3)]\n",
    "%timeit big_custom_ind.tuple_loc[[(1, 3)] * 10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comparison methods"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1       1                    2              \n",
      "custom_p2       3                    4              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  False   True  False  False   True  False\n",
      "2018-01-02  False   True  False   True   True   True\n",
      "2018-01-03   True   True   True   True   True   True\n",
      "2018-01-04   True  False  False   True   True   True\n",
      "2018-01-05   True  False  False   True  False  False\n",
      "485 µs ± 9.08 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "custom_p1       1                    2              \n",
      "custom_p2       3                    4              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  False   True  False  False   True  False\n",
      "2018-01-02  False   True  False   True   True   True\n",
      "2018-01-03   True   True   True   True   True   True\n",
      "2018-01-04   True  False  False   True   True   True\n",
      "2018-01-05   True  False  False   True  False  False\n",
      "3.32 ms ± 6.22 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "print(custom_ind.o1 > 2)\n",
    "%timeit big_custom_ind.o1.values > 2 # don't even try pandas\n",
    "\n",
    "print(custom_ind.o1_above(2))\n",
    "%timeit big_custom_ind.o1_above(2) # slower than numpy because of constructing dataframe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "custom_p1       1                    2                    1                \\\n",
      "custom_p2       3                    4                    3                 \n",
      "                a      b      c      a      b      c      a      b      c   \n",
      "2018-01-01  False   True  False  False   True  False  False   True  False   \n",
      "2018-01-02  False   True  False   True   True   True  False   True  False   \n",
      "2018-01-03   True   True   True   True   True   True  False  False  False   \n",
      "2018-01-04   True  False  False   True   True   True   True  False  False   \n",
      "2018-01-05   True  False  False   True  False  False   True  False  False   \n",
      "\n",
      "custom_p1       2                \n",
      "custom_p2       4                \n",
      "                a      b      c  \n",
      "2018-01-01  False   True  False  \n",
      "2018-01-02   True   True   True  \n",
      "2018-01-03   True   True   True  \n",
      "2018-01-04   True   True   True  \n",
      "2018-01-05   True  False  False  \n",
      "1.37 ms ± 45.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "custom_o1_above      2                                         3         \\\n",
      "custom_p1            1                    2                    1          \n",
      "custom_p2            3                    4                    3          \n",
      "                     a      b      c      a      b      c      a      b   \n",
      "2018-01-01       False   True  False  False   True  False  False   True   \n",
      "2018-01-02       False   True  False   True   True   True  False   True   \n",
      "2018-01-03        True   True   True   True   True   True  False  False   \n",
      "2018-01-04        True  False  False   True   True   True   True  False   \n",
      "2018-01-05        True  False  False   True  False  False   True  False   \n",
      "\n",
      "custom_o1_above                              \n",
      "custom_p1                   2                \n",
      "custom_p2                   4                \n",
      "                     c      a      b      c  \n",
      "2018-01-01       False  False   True  False  \n",
      "2018-01-02       False   True   True   True  \n",
      "2018-01-03       False   True   True   True  \n",
      "2018-01-04       False   True   True   True  \n",
      "2018-01-05       False   True  False  False  \n",
      "8.31 ms ± 85.1 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
     ]
    }
   ],
   "source": [
    "print(pd.concat((custom_ind.o1 > 2, custom_ind.o1 > 3), axis=1))\n",
    "%timeit np.hstack((big_custom_ind.o1.values > 2, big_custom_ind.o1.values > 3))\n",
    "\n",
    "print(custom_ind.o1_above([2, 3]))\n",
    "%timeit big_custom_ind.o1_above([2, 3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TA-Lib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "ts = pd.DataFrame({\n",
    "    'a': [1, 2, 3, 4, np.nan],\n",
    "    'b': [np.nan, 4, 3, 2, 1],\n",
    "    'c': [1, 2, np.nan, 2, 1]\n",
    "}, index=pd.DatetimeIndex([\n",
    "    datetime(2018, 1, 1),\n",
    "    datetime(2018, 1, 2),\n",
    "    datetime(2018, 1, 3),\n",
    "    datetime(2018, 1, 4),\n",
    "    datetime(2018, 1, 5)\n",
    "]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01    NaN\n",
      "2018-01-02    1.5\n",
      "2018-01-03    2.5\n",
      "2018-01-04    3.5\n",
      "2018-01-05    4.5\n",
      "Name: (2, a), dtype: float64\n",
      "sma_timeperiod    2          \n",
      "                  a    b    c\n",
      "2018-01-01      NaN  NaN  NaN\n",
      "2018-01-02      1.5  4.5  1.5\n",
      "2018-01-03      2.5  3.5  2.5\n",
      "2018-01-04      3.5  2.5  2.5\n",
      "2018-01-05      4.5  1.5  1.5\n",
      "sma_timeperiod    2              3               \n",
      "                  a    b    c    a    b         c\n",
      "2018-01-01      NaN  NaN  NaN  NaN  NaN       NaN\n",
      "2018-01-02      1.5  4.5  1.5  NaN  NaN       NaN\n",
      "2018-01-03      2.5  3.5  2.5  2.0  4.0  2.000000\n",
      "2018-01-04      3.5  2.5  2.5  3.0  3.0  2.333333\n",
      "2018-01-05      4.5  1.5  1.5  4.0  2.0  2.000000\n"
     ]
    }
   ],
   "source": [
    "SMA = vbt.talib('SMA')\n",
    "\n",
    "print(SMA.run(close['a'], 2).real)\n",
    "print(SMA.run(close, 2).real)\n",
    "print(SMA.run(close, [2, 3]).real)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "13 ms ± 226 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "80.1 ms ± 1.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "99 ms ± 2.78 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "22.3 ms ± 572 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit SMA.run(big_close)\n",
    "%timeit SMA.run(big_close, np.arange(2, 10))\n",
    "%timeit SMA.run(big_close, np.full(10, 2))\n",
    "%timeit SMA.run(big_close, np.full(10, 2), run_unique=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  3  3  3  3  3  3  3\n",
      "  3  3  3  3  3  3  3  3  3  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4\n",
      "  5  5  5  5  5  5  5  5  5  5  5  5  5  5  6  6  6  6  6  6  6  6  6  6\n",
      "  6  6  6  7  7  7  7  7  7  7  7  7  7  7  7  8  8  8  8  8  8  8  8  8\n",
      "  8  8  9  9  9  9  9  9  9  9  9  9 10 10 10 10 10 10 10 10 10 11 11 11\n",
      " 11 11 11 11 11 12 12 12 12 12 12 12 13 13 13 13 13 13 14 14 14 14 14 15\n",
      " 15 15 15 16 16 16 17 17 18]\n",
      "[ 3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19  4  5  6  7  8  9 10\n",
      " 11 12 13 14 15 16 17 18 19  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19\n",
      "  6  7  8  9 10 11 12 13 14 15 16 17 18 19  7  8  9 10 11 12 13 14 15 16\n",
      " 17 18 19  8  9 10 11 12 13 14 15 16 17 18 19  9 10 11 12 13 14 15 16 17\n",
      " 18 19 10 11 12 13 14 15 16 17 18 19 11 12 13 14 15 16 17 18 19 12 13 14\n",
      " 15 16 17 18 19 13 14 15 16 17 18 19 14 15 16 17 18 19 15 16 17 18 19 16\n",
      " 17 18 19 17 18 19 18 19 19]\n"
     ]
    }
   ],
   "source": [
    "comb = itertools.combinations(np.arange(2, 20), 2)\n",
    "fast_windows, slow_windows = np.asarray(list(comb)).transpose()\n",
    "print(fast_windows)\n",
    "print(slow_windows)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4.04 s ± 652 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1.51 s ± 287 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit SMA.run(big_close, fast_windows), SMA.run(big_close, slow_windows) # individual caching\n",
    "%timeit SMA.run_combs(big_close, np.arange(2, 20)) # mutual caching"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.27 s ± 40.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "1.2 s ± 5.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit vbt.MA.run(big_close, fast_windows), vbt.MA.run(big_close, slow_windows) # the same using Numba\n",
    "%timeit vbt.MA.run_combs(big_close, np.arange(2, 20))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/base/accessors.py:667: RuntimeWarning: invalid value encountered in greater\n",
      "  result = combine_func(inputs[0], inputs[1], *args, **kwargs)\n",
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/base/accessors.py:667: RuntimeWarning: invalid value encountered in less\n",
      "  result = combine_func(inputs[0], inputs[1], *args, **kwargs)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sma_1_timeperiod      2                                         3         \\\n",
      "sma_2_timeperiod      3                    4                    4          \n",
      "                      a      b      c      a      b      c      a      b   \n",
      "2018-01-01        False  False  False  False  False  False  False  False   \n",
      "2018-01-02        False  False  False  False  False  False  False  False   \n",
      "2018-01-03         True  False   True  False  False  False  False  False   \n",
      "2018-01-04        False  False  False   True  False   True   True  False   \n",
      "2018-01-05        False  False  False  False  False  False  False  False   \n",
      "\n",
      "sma_1_timeperiod         \n",
      "sma_2_timeperiod         \n",
      "                      c  \n",
      "2018-01-01        False  \n",
      "2018-01-02        False  \n",
      "2018-01-03        False  \n",
      "2018-01-04         True  \n",
      "2018-01-05        False  \n",
      "sma_1_timeperiod      2                                         3         \\\n",
      "sma_2_timeperiod      3                    4                    4          \n",
      "                      a      b      c      a      b      c      a      b   \n",
      "2018-01-01        False  False  False  False  False  False  False  False   \n",
      "2018-01-02        False  False  False  False  False  False  False  False   \n",
      "2018-01-03        False   True  False  False  False  False  False  False   \n",
      "2018-01-04        False  False  False  False   True  False  False   True   \n",
      "2018-01-05        False  False   True  False  False   True  False  False   \n",
      "\n",
      "sma_1_timeperiod         \n",
      "sma_2_timeperiod         \n",
      "                      c  \n",
      "2018-01-01        False  \n",
      "2018-01-02        False  \n",
      "2018-01-03        False  \n",
      "2018-01-04        False  \n",
      "2018-01-05        False  \n"
     ]
    }
   ],
   "source": [
    "sma1, sma2 = SMA.run_combs(close, [2, 3, 4])\n",
    "print(sma1.real_crossed_above(sma2))\n",
    "print(sma1.real_crossed_below(sma2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['__annotations__',\n",
       " '__class__',\n",
       " '__delattr__',\n",
       " '__dict__',\n",
       " '__dir__',\n",
       " '__doc__',\n",
       " '__eq__',\n",
       " '__format__',\n",
       " '__ge__',\n",
       " '__getattribute__',\n",
       " '__getitem__',\n",
       " '__gt__',\n",
       " '__hash__',\n",
       " '__init__',\n",
       " '__init_subclass__',\n",
       " '__le__',\n",
       " '__lt__',\n",
       " '__module__',\n",
       " '__ne__',\n",
       " '__new__',\n",
       " '__reduce__',\n",
       " '__reduce_ex__',\n",
       " '__repr__',\n",
       " '__setattr__',\n",
       " '__sizeof__',\n",
       " '__str__',\n",
       " '__subclasshook__',\n",
       " '__weakref__',\n",
       " '_in_output_names',\n",
       " '_input_names',\n",
       " '_metrics',\n",
       " '_output_flags',\n",
       " '_output_names',\n",
       " '_param_names',\n",
       " '_run',\n",
       " '_run_combs',\n",
       " 'apply_func',\n",
       " 'build_metrics_doc',\n",
       " 'close',\n",
       " 'close_above',\n",
       " 'close_below',\n",
       " 'close_equal',\n",
       " 'close_stats',\n",
       " 'config',\n",
       " 'copy',\n",
       " 'custom_func',\n",
       " 'deep_getattr',\n",
       " 'dumps',\n",
       " 'iloc',\n",
       " 'in_output_names',\n",
       " 'indexing_func',\n",
       " 'indexing_kwargs',\n",
       " 'input_names',\n",
       " 'level_names',\n",
       " 'load',\n",
       " 'loads',\n",
       " 'loc',\n",
       " 'lowerband',\n",
       " 'lowerband_above',\n",
       " 'lowerband_below',\n",
       " 'lowerband_equal',\n",
       " 'lowerband_stats',\n",
       " 'matype_list',\n",
       " 'matype_loc',\n",
       " 'metrics',\n",
       " 'middleband',\n",
       " 'middleband_above',\n",
       " 'middleband_below',\n",
       " 'middleband_equal',\n",
       " 'middleband_stats',\n",
       " 'nbdevdn_list',\n",
       " 'nbdevdn_loc',\n",
       " 'nbdevup_list',\n",
       " 'nbdevup_loc',\n",
       " 'output_flags',\n",
       " 'output_names',\n",
       " 'override_metrics_doc',\n",
       " 'param_names',\n",
       " 'post_resolve_attr',\n",
       " 'pre_resolve_attr',\n",
       " 'regroup',\n",
       " 'resolve_attr',\n",
       " 'resolve_self',\n",
       " 'run',\n",
       " 'run_combs',\n",
       " 'save',\n",
       " 'select_one',\n",
       " 'select_one_from_obj',\n",
       " 'self_aliases',\n",
       " 'short_name',\n",
       " 'stats',\n",
       " 'stats_defaults',\n",
       " 'timeperiod_list',\n",
       " 'timeperiod_loc',\n",
       " 'to_doc',\n",
       " 'tuple_loc',\n",
       " 'update_config',\n",
       " 'upperband',\n",
       " 'upperband_above',\n",
       " 'upperband_below',\n",
       " 'upperband_equal',\n",
       " 'upperband_stats',\n",
       " 'wrapper',\n",
       " 'writeable_attrs',\n",
       " 'xs']"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dir(vbt.talib('BBANDS'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "              a    b    c\n",
      "2018-01-01  NaN  NaN  NaN\n",
      "2018-01-02  1.5  4.5  1.5\n",
      "2018-01-03  2.5  3.5  2.5\n",
      "2018-01-04  3.5  2.5  2.5\n",
      "2018-01-05  4.5  1.5  1.5\n",
      "                   a         b         c\n",
      "2018-01-01       NaN       NaN       NaN\n",
      "2018-01-02       NaN       NaN       NaN\n",
      "2018-01-03  2.428571  3.571429  2.428571\n",
      "2018-01-04  3.266667  2.733333  2.200000\n",
      "2018-01-05  4.161290  1.838710  1.580645\n",
      "sma_timeperiod    2          \n",
      "                  a    b    c\n",
      "2018-01-01      NaN  NaN  NaN\n",
      "2018-01-02      1.5  4.5  1.5\n",
      "2018-01-03      2.5  3.5  2.5\n",
      "2018-01-04      3.5  2.5  2.5\n",
      "2018-01-05      4.5  1.5  1.5\n",
      "ma_window      2                 3                \n",
      "ma_ewm     False              True                \n",
      "               a    b    c       a       b       c\n",
      "2018-01-01   NaN  NaN  NaN     NaN     NaN     NaN\n",
      "2018-01-02   1.5  4.5  1.5     NaN     NaN     NaN\n",
      "2018-01-03   2.5  3.5  2.5  2.2500  3.7500  2.2500\n",
      "2018-01-04   3.5  2.5  2.5  3.1250  2.8750  2.1250\n",
      "2018-01-05   4.5  1.5  1.5  4.0625  1.9375  1.5625\n"
     ]
    }
   ],
   "source": [
    "print(close.rolling(2).mean())\n",
    "print(close.ewm(span=3, min_periods=3).mean())\n",
    "print(vbt.talib('SMA').run(close, timeperiod=2).real)\n",
    "print(vbt.MA.run(close, [2, 3], ewm=[False, True]).ma)  # adjust=False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "49 ms ± 143 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "12.6 ms ± 181 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "7.39 ms ± 58.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "12.5 ms ± 391 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "# One window\n",
    "%timeit big_close.rolling(2).mean() # pandas\n",
    "%timeit vbt.talib('SMA').run(big_close, timeperiod=2)\n",
    "%timeit vbt.MA.run(big_close, 2, return_cache=True) # cache only\n",
    "%timeit vbt.MA.run(big_close, 2) # with pre+postprocessing and still beats pandas\n",
    "\n",
    "print(vbt.MA.run(big_close, 2).ma.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "406 ms ± 1.24 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "68.9 ms ± 347 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "64.6 ms ± 181 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "64.3 ms ± 266 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "50.1 ms ± 355 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "37.9 ms ± 3.98 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "(1000, 8000)\n"
     ]
    }
   ],
   "source": [
    "# Multiple windows\n",
    "%timeit pd.concat([big_close.rolling(i).mean() for i in np.arange(2, 10)])\n",
    "%timeit vbt.talib('SMA').run(big_close, np.arange(2, 10))\n",
    "%timeit vbt.MA.run(big_close, np.arange(2, 10))\n",
    "%timeit vbt.MA.run(big_close, np.arange(2, 10), run_unique=True)\n",
    "%timeit vbt.MA.run(big_close, np.arange(2, 10), return_cache=True) # cache only\n",
    "cache = vbt.MA.run(big_close, np.arange(2, 10), return_cache=True)\n",
    "%timeit vbt.MA.run(big_close, np.arange(2, 10), use_cache=cache) # using cache\n",
    "\n",
    "print(vbt.MA.run(big_close, np.arange(2, 10)).ma.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "517 ms ± 6.51 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "88.9 ms ± 3.68 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "25.7 ms ± 61.7 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "26.2 ms ± 188 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "6.61 ms ± 346 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "(1000, 10000)\n"
     ]
    }
   ],
   "source": [
    "# One window repeated\n",
    "%timeit pd.concat([big_close.rolling(i).mean() for i in np.full(10, 2)])\n",
    "%timeit vbt.talib('SMA').run(big_close, np.full(10, 2))\n",
    "%timeit vbt.MA.run(big_close, np.full(10, 2))\n",
    "%timeit vbt.MA.run(big_close, np.full(10, 2), run_unique=True)  # slower for large inputs\n",
    "%timeit vbt.MA.run(big_close, np.full(10, 2), return_cache=True)\n",
    "\n",
    "print(vbt.MA.run(big_close, np.full(10, 2)).ma.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "71.6 ms ± 158 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "10.7 ms ± 127 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "4.51 ms ± 57.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "4.35 ms ± 36 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "613 µs ± 2.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "%timeit pd.concat([big_close.iloc[:, :10].rolling(i).mean() for i in np.full(100, 2)])\n",
    "%timeit vbt.talib('SMA').run(big_close.iloc[:, :10], np.full(100, 2))\n",
    "%timeit vbt.MA.run(big_close.iloc[:, :10], np.full(100, 2))\n",
    "%timeit vbt.MA.run(big_close.iloc[:, :10], np.full(100, 2), run_unique=True)  # faster for smaller inputs\n",
    "%timeit vbt.MA.run(big_close.iloc[:, :10], np.full(100, 2), return_cache=True)\n",
    "\n",
    "print(vbt.MA.run(big_close.iloc[:, :10], np.full(100, 2)).ma.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ma_window      2                 3                \n",
      "ma_ewm     False              True                \n",
      "               a    b    c       a       b       c\n",
      "2018-01-01   NaN  NaN  NaN     NaN     NaN     NaN\n",
      "2018-01-02   1.5  4.5  1.5     NaN     NaN     NaN\n",
      "2018-01-03   2.5  3.5  2.5  2.2500  3.7500  2.2500\n",
      "2018-01-04   3.5  2.5  2.5  3.1250  2.8750  2.1250\n",
      "2018-01-05   4.5  1.5  1.5  4.0625  1.9375  1.5625\n"
     ]
    }
   ],
   "source": [
    "ma = vbt.MA.run(close, [2, 3], ewm=[False, True])\n",
    "\n",
    "print(ma.ma)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg class=\"main-svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"700\" height=\"350\" style=\"\" viewBox=\"0 0 700 350\"><rect x=\"0\" y=\"0\" width=\"700\" height=\"350\" style=\"fill: rgb(255, 255, 255); fill-opacity: 1;\"/><defs id=\"defs-66290f\"><g class=\"clips\"><clipPath id=\"clip66290fxyplot\" class=\"plotclip\"><rect width=\"640\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip66290fx\"><rect x=\"30\" y=\"0\" width=\"640\" height=\"350\"/></clipPath><clipPath class=\"axesclip\" id=\"clip66290fy\"><rect x=\"0\" y=\"46\" width=\"700\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip66290fxy\"><rect x=\"30\" y=\"46\" width=\"640\" height=\"261\"/></clipPath></g><g class=\"gradients\"/></defs><g class=\"bglayer\"><rect class=\"bg\" x=\"30\" y=\"46\" width=\"640\" height=\"261\" style=\"fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;\"/></g><g class=\"layer-below\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"cartesianlayer\"><g class=\"subplot xy\"><g class=\"layer-subplot\"><g class=\"shapelayer\"/><g class=\"imagelayer\"/></g><g class=\"gridlayer\"><g class=\"x\"><path class=\"xgrid crisp\" transform=\"translate(65.75,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(207.87,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(350,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(492.13,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(634.25,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g><g class=\"y\"><path class=\"ygrid crisp\" transform=\"translate(0,290.2)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,233.35)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,176.5)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,119.65)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,62.8)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g></g><g class=\"zerolinelayer\"/><path class=\"xlines-below\"/><path class=\"ylines-below\"/><g class=\"overlines-below\"/><g class=\"xaxislayer-below\"/><g class=\"yaxislayer-below\"/><g class=\"overaxes-below\"/><g class=\"plot\" transform=\"translate(30,46)\" clip-path=\"url('#clip66290fxyplot')\"><g class=\"scatterlayer mlayer\"><g class=\"trace scatter trace243e3c82-354d-4ad0-ac7d-6096633afa11\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M35.75,244.2L604.25,16.8\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(35.75,244.2)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(177.87,187.35)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(320,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(462.13,73.65)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(604.25,16.8)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g><g class=\"text\"/></g><g class=\"trace scatter trace64dbe725-b602-4ecd-bc47-9c089fd6fb53\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M177.87,215.78L604.25,45.22\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(255, 127, 14); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(177.87,215.78)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(320,158.92)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(462.13,102.07)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(604.25,45.22)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/></g><g class=\"text\"/></g></g></g><g class=\"overplot\"/><path class=\"xlines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><path class=\"ylines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><g class=\"overlines-above\"/><g class=\"xaxislayer-above\"><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(65.75,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\"><tspan class=\"line\" dy=\"0em\" x=\"0\" y=\"320\">Jan 1</tspan><tspan class=\"line\" dy=\"1.3em\" x=\"0\" y=\"320\">2018</tspan></text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(207.87,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 2</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(350,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 3</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(492.13,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 4</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(634.25,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 5</text></g></g><g class=\"yaxislayer-above\"><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,290.2)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">1</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,233.35)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">2</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,176.5)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">3</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,119.65)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">4</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,62.8)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">5</text></g></g><g class=\"overaxes-above\"/></g></g><g class=\"polarlayer\"/><g class=\"ternarylayer\"/><g class=\"geolayer\"/><g class=\"funnelarealayer\"/><g class=\"pielayer\"/><g class=\"treemaplayer\"/><g class=\"sunburstlayer\"/><g class=\"glimages\"/><defs id=\"topdefs-66290f\"><g class=\"clips\"/><clipPath id=\"legend66290f\"><rect width=\"141\" height=\"29\" x=\"0\" y=\"0\"/></clipPath></defs><g class=\"layer-above\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"infolayer\"><g class=\"legend\" pointer-events=\"all\" transform=\"translate(529,11.779999999999994)\"><rect class=\"bg\" shape-rendering=\"crispEdges\" style=\"stroke: rgb(68, 68, 68); stroke-opacity: 1; fill: rgb(255, 255, 255); fill-opacity: 1; stroke-width: 0px;\" width=\"141\" height=\"29\" x=\"0\" y=\"0\"/><g class=\"scrollbox\" transform=\"\" clip-path=\"url('#legend66290f')\"><g class=\"groups\"><g class=\"traces\" transform=\"translate(0,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Close</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"74.859375\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g><g class=\"traces\" transform=\"translate(77.359375,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">MA</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(255, 127, 14); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"60.828125\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g></g></g><rect class=\"scrollbar\" rx=\"20\" ry=\"3\" width=\"0\" height=\"0\" style=\"fill: rgb(128, 139, 164); fill-opacity: 1;\" x=\"0\" y=\"0\"/></g><g class=\"g-gtitle\"/><g class=\"g-xtitle\"/><g class=\"g-ytitle\"/></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "ma[(2, False, 'a')].plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MSTD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "              a    b    c\n",
      "2018-01-01  NaN  NaN  NaN\n",
      "2018-01-02  0.5  0.5  0.5\n",
      "2018-01-03  0.5  0.5  0.5\n",
      "2018-01-04  0.5  0.5  0.5\n",
      "2018-01-05  0.5  0.5  0.5\n",
      "                   a         b         c\n",
      "2018-01-01       NaN       NaN       NaN\n",
      "2018-01-02       NaN       NaN       NaN\n",
      "2018-01-03  0.963624  0.963624  0.963624\n",
      "2018-01-04  1.177164  1.177164  0.686607\n",
      "2018-01-05  1.345243  1.345243  0.881714\n",
      "stddev_timeperiod    2          \n",
      "                     a    b    c\n",
      "2018-01-01         NaN  NaN  NaN\n",
      "2018-01-02         0.5  0.5  0.5\n",
      "2018-01-03         0.5  0.5  0.5\n",
      "2018-01-04         0.5  0.5  0.5\n",
      "2018-01-05         0.5  0.5  0.5\n",
      "mstd_window     2                   3                    \n",
      "mstd_ewm    False                True                    \n",
      "                a    b    c         a         b         c\n",
      "2018-01-01    NaN  NaN  NaN       NaN       NaN       NaN\n",
      "2018-01-02    0.5  0.5  0.5       NaN       NaN       NaN\n",
      "2018-01-03    0.5  0.5  0.5  1.048809  1.048809  1.048809\n",
      "2018-01-04    0.5  0.5  0.5  1.300183  1.300183  0.740013\n",
      "2018-01-05    0.5  0.5  0.5  1.469294  1.469294  0.864326\n"
     ]
    }
   ],
   "source": [
    "print(close.rolling(2).std(ddof=0))\n",
    "print(close.ewm(span=3, min_periods=3).std(ddof=0))\n",
    "print(vbt.talib('STDDEV').run(close, timeperiod=2).real)  \n",
    "print(vbt.MSTD.run(close, [2, 3], ewm=[False, True]).mstd)  # adjust=False, ddof=0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "65.2 ms ± 486 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "13.7 ms ± 281 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "11.4 ms ± 669 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "# One window\n",
    "%timeit big_close.rolling(2).std()\n",
    "%timeit vbt.talib('STDDEV').run(big_close, timeperiod=2)\n",
    "%timeit vbt.MSTD.run(big_close, 2)\n",
    "\n",
    "print(vbt.MSTD.run(big_close, 2).mstd.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "534 ms ± 1.43 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "80.3 ms ± 1.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "81.8 ms ± 973 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 8000)\n"
     ]
    }
   ],
   "source": [
    "# Multiple windows\n",
    "%timeit pd.concat([big_close.rolling(i).std() for i in np.arange(2, 10)])\n",
    "%timeit vbt.talib('STDDEV').run(big_close, timeperiod=np.arange(2, 10))\n",
    "%timeit vbt.MSTD.run(big_close, np.arange(2, 10))\n",
    "\n",
    "print(vbt.MSTD.run(big_close, np.arange(2, 10)).mstd.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "98 ms ± 317 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "27.8 ms ± 44.6 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 10000)\n"
     ]
    }
   ],
   "source": [
    "# One window repeated\n",
    "%timeit vbt.talib('STDDEV').run(big_close, timeperiod=np.full(10, 2))\n",
    "%timeit vbt.MSTD.run(big_close, window=np.full(10, 2))\n",
    "\n",
    "print(vbt.MSTD.run(big_close, window=np.full(10, 2)).close.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "mstd_window     2                   3                    \n",
      "mstd_ewm    False                True                    \n",
      "                a    b    c         a         b         c\n",
      "2018-01-01    NaN  NaN  NaN       NaN       NaN       NaN\n",
      "2018-01-02    0.5  0.5  0.5       NaN       NaN       NaN\n",
      "2018-01-03    0.5  0.5  0.5  1.048809  1.048809  1.048809\n",
      "2018-01-04    0.5  0.5  0.5  1.300183  1.300183  0.740013\n",
      "2018-01-05    0.5  0.5  0.5  1.469294  1.469294  0.864326\n"
     ]
    }
   ],
   "source": [
    "mstd = vbt.MSTD.run(close, [2, 3], [False, True])\n",
    "\n",
    "print(mstd.mstd)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg class=\"main-svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"700\" height=\"350\" style=\"\" viewBox=\"0 0 700 350\"><rect x=\"0\" y=\"0\" width=\"700\" height=\"350\" style=\"fill: rgb(255, 255, 255); fill-opacity: 1;\"/><defs id=\"defs-5b3e5b\"><g class=\"clips\"><clipPath id=\"clip5b3e5bxyplot\" class=\"plotclip\"><rect width=\"628\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip5b3e5bx\"><rect x=\"42\" y=\"0\" width=\"628\" height=\"350\"/></clipPath><clipPath class=\"axesclip\" id=\"clip5b3e5by\"><rect x=\"0\" y=\"46\" width=\"700\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip5b3e5bxy\"><rect x=\"42\" y=\"46\" width=\"628\" height=\"261\"/></clipPath></g><g class=\"gradients\"/></defs><g class=\"bglayer\"><rect class=\"bg\" x=\"42\" y=\"46\" width=\"628\" height=\"261\" style=\"fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;\"/></g><g class=\"layer-below\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"cartesianlayer\"><g class=\"subplot xy\"><g class=\"layer-subplot\"><g class=\"shapelayer\"/><g class=\"imagelayer\"/></g><g class=\"gridlayer\"><g class=\"x\"><path class=\"xgrid crisp\" transform=\"translate(77.15,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(216.58,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(356,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(495.42,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(634.85,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g><g class=\"y\"><path class=\"ygrid crisp\" transform=\"translate(0,176.5)\" d=\"M42,0h628\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,111.25)\" d=\"M42,0h628\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g></g><g class=\"zerolinelayer\"><path class=\"yzl zl crisp\" transform=\"translate(0,241.75)\" d=\"M42,0h628\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 2px;\"/></g><path class=\"xlines-below\"/><path class=\"ylines-below\"/><g class=\"overlines-below\"/><g class=\"xaxislayer-below\"/><g class=\"yaxislayer-below\"/><g class=\"overaxes-below\"/><g class=\"plot\" transform=\"translate(42,46)\" clip-path=\"url('#clip5b3e5bxyplot')\"><g class=\"scatterlayer mlayer\"><g class=\"trace scatter tracee67d7d3f-ce5e-4131-a96a-243dc24a40db\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M174.58,130.5L592.85,130.5\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(174.58,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(314,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(453.42,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(592.85,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g><g class=\"text\"/></g></g></g><g class=\"overplot\"/><path class=\"xlines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><path class=\"ylines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><g class=\"overlines-above\"/><g class=\"xaxislayer-above\"><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(77.15,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\"><tspan class=\"line\" dy=\"0em\" x=\"0\" y=\"320\">Jan 1</tspan><tspan class=\"line\" dy=\"1.3em\" x=\"0\" y=\"320\">2018</tspan></text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(216.58,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 2</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(356,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 3</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(495.42,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 4</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(634.85,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 5</text></g></g><g class=\"yaxislayer-above\"><g class=\"ytick\"><text text-anchor=\"end\" x=\"41\" y=\"4.199999999999999\" transform=\"translate(0,307)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">−0.5</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"41\" y=\"4.199999999999999\" transform=\"translate(0,241.75)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"41\" y=\"4.199999999999999\" transform=\"translate(0,176.5)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.5</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"41\" y=\"4.199999999999999\" transform=\"translate(0,111.25)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">1</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"41\" y=\"4.199999999999999\" transform=\"translate(0,46)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">1.5</text></g></g><g class=\"overaxes-above\"/></g></g><g class=\"polarlayer\"/><g class=\"ternarylayer\"/><g class=\"geolayer\"/><g class=\"funnelarealayer\"/><g class=\"pielayer\"/><g class=\"treemaplayer\"/><g class=\"sunburstlayer\"/><g class=\"glimages\"/><defs id=\"topdefs-5b3e5b\"><g class=\"clips\"/><clipPath id=\"legend5b3e5b\"><rect width=\"80\" height=\"29\" x=\"0\" y=\"0\"/></clipPath></defs><g class=\"layer-above\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"infolayer\"><g class=\"legend\" pointer-events=\"all\" transform=\"translate(590,11.779999999999994)\"><rect class=\"bg\" shape-rendering=\"crispEdges\" style=\"stroke: rgb(68, 68, 68); stroke-opacity: 1; fill: rgb(255, 255, 255); fill-opacity: 1; stroke-width: 0px;\" width=\"80\" height=\"29\" x=\"0\" y=\"0\"/><g class=\"scrollbox\" transform=\"\" clip-path=\"url('#legend5b3e5b')\"><g class=\"groups\"><g class=\"traces\" transform=\"translate(0,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">MSTD</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"77.46875\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g></g></g><rect class=\"scrollbar\" rx=\"20\" ry=\"3\" width=\"0\" height=\"0\" style=\"fill: rgb(128, 139, 164); fill-opacity: 1;\" x=\"0\" y=\"0\"/></g><g class=\"g-gtitle\"/><g class=\"g-xtitle\"/><g class=\"g-ytitle\"/></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "mstd[(2, False, 'a')].plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## BBANDS"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01    NaN\n",
      "2018-01-02    2.5\n",
      "2018-01-03    3.5\n",
      "2018-01-04    4.5\n",
      "2018-01-05    5.5\n",
      "Name: (2, 2, a), dtype: float64\n",
      "2018-01-01    NaN\n",
      "2018-01-02    1.5\n",
      "2018-01-03    2.5\n",
      "2018-01-04    3.5\n",
      "2018-01-05    4.5\n",
      "Name: (2, 2, a), dtype: float64\n",
      "2018-01-01    NaN\n",
      "2018-01-02    0.5\n",
      "2018-01-03    1.5\n",
      "2018-01-04    2.5\n",
      "2018-01-05    3.5\n",
      "Name: (2, 2, a), dtype: float64\n",
      "bbands_timeperiod    2          \n",
      "bbands_nbdevup       2          \n",
      "bbands_nbdevdn       2          \n",
      "                     a    b    c\n",
      "2018-01-01         NaN  NaN  NaN\n",
      "2018-01-02         2.5  5.5  2.5\n",
      "2018-01-03         3.5  4.5  3.5\n",
      "2018-01-04         4.5  3.5  3.5\n",
      "2018-01-05         5.5  2.5  2.5\n",
      "bbands_timeperiod    2          \n",
      "bbands_nbdevup       2          \n",
      "bbands_nbdevdn       2          \n",
      "                     a    b    c\n",
      "2018-01-01         NaN  NaN  NaN\n",
      "2018-01-02         1.5  4.5  1.5\n",
      "2018-01-03         2.5  3.5  2.5\n",
      "2018-01-04         3.5  2.5  2.5\n",
      "2018-01-05         4.5  1.5  1.5\n",
      "bbands_timeperiod    2          \n",
      "bbands_nbdevup       2          \n",
      "bbands_nbdevdn       2          \n",
      "                     a    b    c\n",
      "2018-01-01         NaN  NaN  NaN\n",
      "2018-01-02         0.5  3.5  0.5\n",
      "2018-01-03         1.5  2.5  1.5\n",
      "2018-01-04         2.5  1.5  1.5\n",
      "2018-01-05         3.5  0.5  0.5\n",
      "bb_window      2          \n",
      "bb_ewm     False          \n",
      "bb_alpha       2          \n",
      "               a    b    c\n",
      "2018-01-01   NaN  NaN  NaN\n",
      "2018-01-02   2.5  5.5  2.5\n",
      "2018-01-03   3.5  4.5  3.5\n",
      "2018-01-04   4.5  3.5  3.5\n",
      "2018-01-05   5.5  2.5  2.5\n",
      "bb_window      2          \n",
      "bb_ewm     False          \n",
      "bb_alpha       2          \n",
      "               a    b    c\n",
      "2018-01-01   NaN  NaN  NaN\n",
      "2018-01-02   1.5  4.5  1.5\n",
      "2018-01-03   2.5  3.5  2.5\n",
      "2018-01-04   3.5  2.5  2.5\n",
      "2018-01-05   4.5  1.5  1.5\n",
      "bb_window      2          \n",
      "bb_ewm     False          \n",
      "bb_alpha       2          \n",
      "               a    b    c\n",
      "2018-01-01   NaN  NaN  NaN\n",
      "2018-01-02   0.5  3.5  0.5\n",
      "2018-01-03   1.5  2.5  1.5\n",
      "2018-01-04   2.5  1.5  1.5\n",
      "2018-01-05   3.5  0.5  0.5\n"
     ]
    }
   ],
   "source": [
    "print(vbt.ta('BollingerBands').run(close['a'], window=2, window_dev=2).bollinger_hband)\n",
    "print(vbt.ta('BollingerBands').run(close['a'], window=2, window_dev=2).bollinger_mavg)\n",
    "print(vbt.ta('BollingerBands').run(close['a'], window=2, window_dev=2).bollinger_lband)\n",
    "\n",
    "print(vbt.talib('BBANDS').run(close, timeperiod=2, nbdevup=2, nbdevdn=2).upperband)\n",
    "print(vbt.talib('BBANDS').run(close, timeperiod=2, nbdevup=2, nbdevdn=2).middleband)\n",
    "print(vbt.talib('BBANDS').run(close, timeperiod=2, nbdevup=2, nbdevdn=2).lowerband)\n",
    "\n",
    "print(vbt.BBANDS.run(close, window=2, ewm=False, alpha=2).upper)\n",
    "print(vbt.BBANDS.run(close, window=2, ewm=False, alpha=2).middle)\n",
    "print(vbt.BBANDS.run(close, window=2, ewm=False, alpha=2).lower)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "23 ms ± 367 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "21.6 ms ± 412 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "# One window\n",
    "%timeit vbt.talib('BBANDS').run(big_close, timeperiod=2)\n",
    "%timeit vbt.BBANDS.run(big_close, window=2)\n",
    "\n",
    "print(vbt.BBANDS.run(big_close).close.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "192 ms ± 1.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "185 ms ± 1.42 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 8000)\n"
     ]
    }
   ],
   "source": [
    "# Multiple windows\n",
    "%timeit vbt.talib('BBANDS').run(big_close, timeperiod=np.arange(2, 10))\n",
    "%timeit vbt.BBANDS.run(big_close, window=np.arange(2, 10))\n",
    "\n",
    "print(vbt.BBANDS.run(big_close, window=np.arange(2, 10)).close.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "215 ms ± 1.51 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "100 ms ± 1.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 10000)\n"
     ]
    }
   ],
   "source": [
    "# One window repeated\n",
    "%timeit vbt.talib('BBANDS').run(big_close, timeperiod=np.full(10, 2))\n",
    "%timeit vbt.BBANDS.run(big_close, window=np.full(10, 2))\n",
    "\n",
    "print(vbt.BBANDS.run(big_close, window=np.full(10, 2)).close.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "bb_window      2                         \n",
      "bb_ewm     False                         \n",
      "bb_alpha     1.0            2.0          \n",
      "               a    b    c    a    b    c\n",
      "2018-01-01   NaN  NaN  NaN  NaN  NaN  NaN\n",
      "2018-01-02   1.5  4.5  1.5  1.5  4.5  1.5\n",
      "2018-01-03   2.5  3.5  2.5  2.5  3.5  2.5\n",
      "2018-01-04   3.5  2.5  2.5  3.5  2.5  2.5\n",
      "2018-01-05   4.5  1.5  1.5  4.5  1.5  1.5\n",
      "\n",
      "bb_window      2                         \n",
      "bb_ewm     False                         \n",
      "bb_alpha     1.0            2.0          \n",
      "               a    b    c    a    b    c\n",
      "2018-01-01   NaN  NaN  NaN  NaN  NaN  NaN\n",
      "2018-01-02   2.0  5.0  2.0  2.5  5.5  2.5\n",
      "2018-01-03   3.0  4.0  3.0  3.5  4.5  3.5\n",
      "2018-01-04   4.0  3.0  3.0  4.5  3.5  3.5\n",
      "2018-01-05   5.0  2.0  2.0  5.5  2.5  2.5\n",
      "\n",
      "bb_window      2                         \n",
      "bb_ewm     False                         \n",
      "bb_alpha     1.0            2.0          \n",
      "               a    b    c    a    b    c\n",
      "2018-01-01   NaN  NaN  NaN  NaN  NaN  NaN\n",
      "2018-01-02   1.0  4.0  1.0  0.5  3.5  0.5\n",
      "2018-01-03   2.0  3.0  2.0  1.5  2.5  1.5\n",
      "2018-01-04   3.0  2.0  2.0  2.5  1.5  1.5\n",
      "2018-01-05   4.0  1.0  1.0  3.5  0.5  0.5\n",
      "\n",
      "bb_window      2                            \n",
      "bb_ewm     False                            \n",
      "bb_alpha     1.0             2.0            \n",
      "               a    b    c     a     b     c\n",
      "2018-01-01   NaN  NaN  NaN   NaN   NaN   NaN\n",
      "2018-01-02   1.0  0.0  1.0  0.75  0.25  0.75\n",
      "2018-01-03   1.0  0.0  1.0  0.75  0.25  0.75\n",
      "2018-01-04   1.0  0.0  0.0  0.75  0.25  0.25\n",
      "2018-01-05   1.0  0.0  0.0  0.75  0.25  0.25\n",
      "\n",
      "bb_window          2                                                  \n",
      "bb_ewm         False                                                  \n",
      "bb_alpha         1.0                           2.0                    \n",
      "                   a         b         c         a         b         c\n",
      "2018-01-01       NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-02  0.666667  0.222222  0.666667  1.333333  0.444444  1.333333\n",
      "2018-01-03  0.400000  0.285714  0.400000  0.800000  0.571429  0.800000\n",
      "2018-01-04  0.285714  0.400000  0.400000  0.571429  0.800000  0.800000\n",
      "2018-01-05  0.222222  0.666667  0.666667  0.444444  1.333333  1.333333\n"
     ]
    }
   ],
   "source": [
    "bb = vbt.BBANDS.run(close, window=2, alpha=[1., 2.], ewm=False)\n",
    "\n",
    "print(bb.middle)\n",
    "print()\n",
    "print(bb.upper)\n",
    "print()\n",
    "print(bb.lower)\n",
    "print()\n",
    "print(bb.percent_b)\n",
    "print()\n",
    "print(bb.bandwidth)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "bb_window       2                                   \n",
      "bb_ewm      False                                   \n",
      "bb_alpha      1.0                  2.0              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  False  False  False  False  False  False\n",
      "2018-01-02  False  False  False   True   True   True\n",
      "2018-01-03  False  False  False   True   True   True\n",
      "2018-01-04  False  False  False   True   True   True\n",
      "2018-01-05  False  False  False   True   True   True\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/base/accessors.py:667: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in less\n",
      "\n",
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/base/accessors.py:667: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in greater\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(bb.close_below(bb.upper) & bb.close_above(bb.lower)) # price between bands"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg class=\"main-svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"700\" height=\"350\" style=\"\" viewBox=\"0 0 700 350\"><rect x=\"0\" y=\"0\" width=\"700\" height=\"350\" style=\"fill: rgb(255, 255, 255); fill-opacity: 1;\"/><defs id=\"defs-73c19f\"><g class=\"clips\"><clipPath id=\"clip73c19fxyplot\" class=\"plotclip\"><rect width=\"640\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip73c19fx\"><rect x=\"30\" y=\"0\" width=\"640\" height=\"350\"/></clipPath><clipPath class=\"axesclip\" id=\"clip73c19fy\"><rect x=\"0\" y=\"46\" width=\"700\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip73c19fxy\"><rect x=\"30\" y=\"46\" width=\"640\" height=\"261\"/></clipPath></g><g class=\"gradients\"/></defs><g class=\"bglayer\"><rect class=\"bg\" x=\"30\" y=\"46\" width=\"640\" height=\"261\" style=\"fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;\"/></g><g class=\"layer-below\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"cartesianlayer\"><g class=\"subplot xy\"><g class=\"layer-subplot\"><g class=\"shapelayer\"/><g class=\"imagelayer\"/></g><g class=\"gridlayer\"><g class=\"x\"><path class=\"xgrid crisp\" transform=\"translate(65.75,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(207.87,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(350,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(492.13,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(634.25,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g><g class=\"y\"><path class=\"ygrid crisp\" transform=\"translate(0,290.2)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,233.35)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,176.5)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,119.65)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,62.8)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g></g><g class=\"zerolinelayer\"/><path class=\"xlines-below\"/><path class=\"ylines-below\"/><g class=\"overlines-below\"/><g class=\"xaxislayer-below\"/><g class=\"yaxislayer-below\"/><g class=\"overaxes-below\"/><g class=\"plot\" transform=\"translate(30,46)\" clip-path=\"url('#clip73c19fxyplot')\"><g class=\"scatterlayer mlayer\"><g class=\"trace scatter trace4458ec75-1343-4661-9a7f-63cb306b9d17\" style=\"stroke-miterlimit: 2;\"><g class=\"fills\"><g><path class=\"js-fill\" d=\"M177.87,187.35L604.25,16.8L604.25,73.65L177.87,244.2Z\" style=\"fill: rgb(128, 128, 128); fill-opacity: 0.2; stroke-width: 0;\"/></g></g><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M177.87,244.2L604.25,73.65\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(127, 127, 127); stroke-opacity: 0.75; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(177.87,244.2)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/><path class=\"point\" transform=\"translate(320,187.35)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/><path class=\"point\" transform=\"translate(462.13,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/><path class=\"point\" transform=\"translate(604.25,73.65)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/></g><g class=\"text\"/></g><g class=\"trace scatter tracee9232809-4e71-441f-9f92-9f4f4913b5dd\" style=\"stroke-miterlimit: 2;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M177.87,187.35L604.25,16.8\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(127, 127, 127); stroke-opacity: 0.75; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(177.87,187.35)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/><path class=\"point\" transform=\"translate(320,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/><path class=\"point\" transform=\"translate(462.13,73.65)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/><path class=\"point\" transform=\"translate(604.25,16.8)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/></g><g class=\"text\"/></g><g class=\"trace scatter traceef267832-19ac-450a-ad0a-f468d899846d\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M177.87,215.78L604.25,45.22\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(44, 160, 44); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(177.87,215.78)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(44, 160, 44); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(320,158.92)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(44, 160, 44); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(462.13,102.07)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(44, 160, 44); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(604.25,45.22)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(44, 160, 44); fill-opacity: 1;\"/></g><g class=\"text\"/></g><g class=\"trace scatter trace17e85e99-978d-47ab-a9a5-395305031a63\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M35.75,244.2L604.25,16.8\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(35.75,244.2)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(177.87,187.35)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(320,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(462.13,73.65)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(604.25,16.8)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g><g class=\"text\"/></g></g></g><g class=\"overplot\"/><path class=\"xlines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><path class=\"ylines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><g class=\"overlines-above\"/><g class=\"xaxislayer-above\"><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(65.75,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\"><tspan class=\"line\" dy=\"0em\" x=\"0\" y=\"320\">Jan 1</tspan><tspan class=\"line\" dy=\"1.3em\" x=\"0\" y=\"320\">2018</tspan></text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(207.87,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 2</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(350,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 3</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(492.13,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 4</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(634.25,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 5</text></g></g><g class=\"yaxislayer-above\"><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,290.2)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">1</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,233.35)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">2</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,176.5)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">3</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,119.65)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">4</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,62.8)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">5</text></g></g><g class=\"overaxes-above\"/></g></g><g class=\"polarlayer\"/><g class=\"ternarylayer\"/><g class=\"geolayer\"/><g class=\"funnelarealayer\"/><g class=\"pielayer\"/><g class=\"treemaplayer\"/><g class=\"sunburstlayer\"/><g class=\"glimages\"/><defs id=\"topdefs-73c19f\"><g class=\"clips\"/><clipPath id=\"legend73c19f\"><rect width=\"428\" height=\"29\" x=\"0\" y=\"0\"/></clipPath></defs><g class=\"layer-above\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"infolayer\"><g class=\"legend\" pointer-events=\"all\" transform=\"translate(242,11.779999999999994)\"><rect class=\"bg\" shape-rendering=\"crispEdges\" style=\"stroke: rgb(68, 68, 68); stroke-opacity: 1; fill: rgb(255, 255, 255); fill-opacity: 1; stroke-width: 0px;\" width=\"428\" height=\"29\" x=\"0\" y=\"0\"/><g class=\"scrollbox\" transform=\"\" clip-path=\"url('#legend73c19f')\"><g class=\"groups\"><g class=\"traces\" transform=\"translate(0,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Lower Band</text><g class=\"layers\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(127, 127, 127); stroke-opacity: 0.75; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"113.28125\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g><g class=\"traces\" transform=\"translate(115.78125,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Upper Band</text><g class=\"layers\"><g class=\"legendfill\"><path class=\"js-fill\" d=\"M5,0h30v6h-30z\" style=\"stroke-width: 0; fill: rgb(128, 128, 128); fill-opacity: 0.2;\"/></g><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(127, 127, 127); stroke-opacity: 0.75; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(127, 127, 127); fill-opacity: 0.75;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"113.234375\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g><g class=\"traces\" transform=\"translate(231.515625,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Middle Band</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(44, 160, 44); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(44, 160, 44); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"116.03125\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g><g class=\"traces\" transform=\"translate(350.046875,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Close</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"74.859375\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g></g></g><rect class=\"scrollbar\" rx=\"20\" ry=\"3\" width=\"0\" height=\"0\" style=\"fill: rgb(128, 139, 164); fill-opacity: 1;\" x=\"0\" y=\"0\"/></g><g class=\"g-gtitle\"/><g class=\"g-xtitle\"/><g class=\"g-ytitle\"/></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "bb[(2, False, 1., 'a')].plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## RSI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01      NaN\n",
      "2018-01-02    100.0\n",
      "2018-01-03    100.0\n",
      "2018-01-04    100.0\n",
      "2018-01-05    100.0\n",
      "Name: (2, a), dtype: float64\n",
      "2018-01-01    NaN\n",
      "2018-01-02    0.0\n",
      "2018-01-03    0.0\n",
      "2018-01-04    0.0\n",
      "2018-01-05    0.0\n",
      "Name: (2, b), dtype: float64\n",
      "2018-01-01           NaN\n",
      "2018-01-02    100.000000\n",
      "2018-01-03    100.000000\n",
      "2018-01-04     42.857143\n",
      "2018-01-05     20.000000\n",
      "Name: (2, c), dtype: float64\n",
      "rsi_timeperiod      2            \n",
      "                    a    b      c\n",
      "2018-01-01        NaN  NaN    NaN\n",
      "2018-01-02        NaN  NaN    NaN\n",
      "2018-01-03      100.0  0.0  100.0\n",
      "2018-01-04      100.0  0.0   50.0\n",
      "2018-01-05      100.0  0.0   25.0\n",
      "rsi_window      2                                    \n",
      "rsi_ewm      True                   False            \n",
      "                a    b           c      a    b      c\n",
      "2018-01-01    NaN  NaN         NaN    NaN  NaN    NaN\n",
      "2018-01-02    NaN  NaN         NaN    NaN  NaN    NaN\n",
      "2018-01-03  100.0  0.0  100.000000  100.0  0.0  100.0\n",
      "2018-01-04  100.0  0.0   33.333333  100.0  0.0   50.0\n",
      "2018-01-05  100.0  0.0   11.111111  100.0  0.0    0.0\n"
     ]
    }
   ],
   "source": [
    "print(vbt.ta('RSIIndicator').run(close=close['a'], window=2).rsi)  # alpha=1/n\n",
    "print(vbt.ta('RSIIndicator').run(close=close['b'], window=2).rsi)\n",
    "print(vbt.ta('RSIIndicator').run(close=close['c'], window=2).rsi)\n",
    "print(vbt.talib('RSI').run(close, timeperiod=2).real)\n",
    "print(vbt.RSI.run(close, window=[2, 2], ewm=[True, False]).rsi)  # span=n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19.4 ms ± 149 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "27.6 ms ± 922 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "# One window\n",
    "%timeit vbt.talib('RSI').run(big_close, timeperiod=2)\n",
    "%timeit vbt.RSI.run(big_close, window=2)\n",
    "\n",
    "print(vbt.RSI.run(big_close, window=2).rsi.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "128 ms ± 253 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "139 ms ± 244 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 8000)\n"
     ]
    }
   ],
   "source": [
    "# Multiple windows\n",
    "%timeit vbt.talib('RSI').run(big_close, timeperiod=np.arange(2, 10))\n",
    "%timeit vbt.RSI.run(big_close, window=np.arange(2, 10))\n",
    "\n",
    "print(vbt.RSI.run(big_close, window=np.arange(2, 10)).rsi.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "160 ms ± 214 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "53.6 ms ± 137 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 10000)\n"
     ]
    }
   ],
   "source": [
    "# One window repeated\n",
    "%timeit vbt.talib('RSI').run(big_close, timeperiod=np.full(10, 2))\n",
    "%timeit vbt.RSI.run(big_close, window=np.full(10, 2))\n",
    "\n",
    "print(vbt.RSI.run(big_close, window=np.full(10, 2)).rsi.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rsi_window      2                  3           \n",
      "rsi_ewm     False               True           \n",
      "                a    b      c      a    b     c\n",
      "2018-01-01    NaN  NaN    NaN    NaN  NaN   NaN\n",
      "2018-01-02    NaN  NaN    NaN    NaN  NaN   NaN\n",
      "2018-01-03  100.0  0.0  100.0    NaN  NaN   NaN\n",
      "2018-01-04  100.0  0.0   50.0  100.0  0.0  50.0\n",
      "2018-01-05  100.0  0.0    0.0  100.0  0.0  25.0\n"
     ]
    }
   ],
   "source": [
    "rsi = vbt.RSI.run(close, window=[2, 3], ewm=[False, True])\n",
    "\n",
    "print(rsi.rsi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "rsi_window      2                    3              \n",
      "rsi_ewm     False                 True              \n",
      "                a      b      c      a      b      c\n",
      "2018-01-01  False  False  False  False  False  False\n",
      "2018-01-02  False  False  False  False  False  False\n",
      "2018-01-03   True  False   True  False  False  False\n",
      "2018-01-04   True  False  False   True  False  False\n",
      "2018-01-05   True  False  False   True  False  False\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/base/accessors.py:667: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in greater\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(rsi.rsi_above(70))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg class=\"main-svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"700\" height=\"350\" style=\"\" viewBox=\"0 0 700 350\"><rect x=\"0\" y=\"0\" width=\"700\" height=\"350\" style=\"fill: rgb(255, 255, 255); fill-opacity: 1;\"/><defs id=\"defs-5265e4\"><g class=\"clips\"><clipPath id=\"clip5265e4xyplot\" class=\"plotclip\"><rect width=\"634\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip5265e4x\"><rect x=\"36\" y=\"0\" width=\"634\" height=\"350\"/></clipPath><clipPath class=\"axesclip\" id=\"clip5265e4y\"><rect x=\"0\" y=\"46\" width=\"700\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip5265e4xy\"><rect x=\"36\" y=\"46\" width=\"634\" height=\"261\"/></clipPath></g><g class=\"gradients\"/></defs><g class=\"bglayer\"><rect class=\"bg\" x=\"36\" y=\"46\" width=\"634\" height=\"261\" style=\"fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;\"/></g><g class=\"layer-below\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"cartesianlayer\"><g class=\"subplot xy\"><g class=\"layer-subplot\"><g class=\"shapelayer\"><path data-index=\"0\" fill-rule=\"evenodd\" d=\"M71.45,223.95H634.55V129.05H71.45Z\" clip-path=\"url('#clip5265e4xy')\" style=\"opacity: 0.2; stroke: rgb(0, 0, 0); stroke-opacity: 0; fill: rgb(128, 0, 128); fill-opacity: 1; stroke-width: 0px;\"/></g><g class=\"imagelayer\"/></g><g class=\"gridlayer\"><g class=\"x\"><path class=\"xgrid crisp\" transform=\"translate(71.45,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(212.22,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(353,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(493.78,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(634.55,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g><g class=\"y\"><path class=\"ygrid crisp\" transform=\"translate(0,247.68)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,200.23)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,152.76999999999998)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,105.32)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,57.86)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g></g><g class=\"zerolinelayer\"><path class=\"yzl zl crisp\" transform=\"translate(0,295.14)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 2px;\"/></g><path class=\"xlines-below\"/><path class=\"ylines-below\"/><g class=\"overlines-below\"/><g class=\"xaxislayer-below\"/><g class=\"yaxislayer-below\"/><g class=\"overaxes-below\"/><g class=\"plot\" transform=\"translate(36,46)\" clip-path=\"url('#clip5265e4xyplot')\"><g class=\"scatterlayer mlayer\"><g class=\"trace scatter trace5d7d5745-e3e0-4f4f-aefb-3617bd4eda42\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M317,11.86L598.55,11.86\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(317,11.86)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(457.78,11.86)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(598.55,11.86)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g><g class=\"text\"/></g></g></g><g class=\"overplot\"/><path class=\"xlines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><path class=\"ylines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><g class=\"overlines-above\"/><g class=\"xaxislayer-above\"><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(71.45,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\"><tspan class=\"line\" dy=\"0em\" x=\"0\" y=\"320\">Jan 1</tspan><tspan class=\"line\" dy=\"1.3em\" x=\"0\" y=\"320\">2018</tspan></text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(212.22,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 2</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(353,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 3</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(493.78,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 4</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(634.55,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 5</text></g></g><g class=\"yaxislayer-above\"><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,295.14)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,247.68)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">20</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,200.23)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">40</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,152.76999999999998)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">60</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,105.32)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">80</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,57.86)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">100</text></g></g><g class=\"overaxes-above\"/></g></g><g class=\"polarlayer\"/><g class=\"ternarylayer\"/><g class=\"geolayer\"/><g class=\"funnelarealayer\"/><g class=\"pielayer\"/><g class=\"treemaplayer\"/><g class=\"sunburstlayer\"/><g class=\"glimages\"/><defs id=\"topdefs-5265e4\"><g class=\"clips\"/><clipPath id=\"legend5265e4\"><rect width=\"67\" height=\"29\" x=\"0\" y=\"0\"/></clipPath></defs><g class=\"layer-above\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"infolayer\"><g class=\"legend\" pointer-events=\"all\" transform=\"translate(603,11.779999999999994)\"><rect class=\"bg\" shape-rendering=\"crispEdges\" style=\"stroke: rgb(68, 68, 68); stroke-opacity: 1; fill: rgb(255, 255, 255); fill-opacity: 1; stroke-width: 0px;\" width=\"67\" height=\"29\" x=\"0\" y=\"0\"/><g class=\"scrollbox\" transform=\"\" clip-path=\"url('#legend5265e4')\"><g class=\"groups\"><g class=\"traces\" transform=\"translate(0,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">RSI</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"64.109375\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g></g></g><rect class=\"scrollbar\" rx=\"20\" ry=\"3\" width=\"0\" height=\"0\" style=\"fill: rgb(128, 139, 164); fill-opacity: 1;\" x=\"0\" y=\"0\"/></g><g class=\"g-gtitle\"/><g class=\"g-xtitle\"/><g class=\"g-ytitle\"/></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "rsi[(2, False, 'a')].plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## STOCH"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01          NaN\n",
      "2018-01-02    90.033913\n",
      "2018-01-03    98.459370\n",
      "2018-01-04    81.624981\n",
      "2018-01-05    74.524237\n",
      "Name: (2, 3, a), dtype: float64\n",
      "2018-01-01          NaN\n",
      "2018-01-02          NaN\n",
      "2018-01-03          NaN\n",
      "2018-01-04    90.039421\n",
      "2018-01-05    84.869529\n",
      "Name: (2, 3, a), dtype: float64\n",
      "stochf_fastk_period          2                     \n",
      "stochf_fastd_period          3                     \n",
      "                             a         b          c\n",
      "2018-01-01                 NaN       NaN        NaN\n",
      "2018-01-02                 NaN       NaN        NaN\n",
      "2018-01-03                 NaN       NaN        NaN\n",
      "2018-01-04           81.624981  3.297837  11.941605\n",
      "2018-01-05           74.524237  3.900804   7.395659\n",
      "stochf_fastk_period          2                      \n",
      "stochf_fastd_period          3                      \n",
      "                             a          b          c\n",
      "2018-01-01                 NaN        NaN        NaN\n",
      "2018-01-02                 NaN        NaN        NaN\n",
      "2018-01-03                 NaN        NaN        NaN\n",
      "2018-01-04           90.039421  12.025053  64.904657\n",
      "2018-01-05           84.869529   7.952381  35.000612\n",
      "stoch_k_window          2                      \n",
      "stoch_d_window          3                      \n",
      "                        a          b          c\n",
      "2018-01-01            NaN        NaN        NaN\n",
      "2018-01-02      90.033913  16.118819  97.107794\n",
      "2018-01-03      98.459370  16.658503  85.664573\n",
      "2018-01-04      81.624981   3.297837  11.941605\n",
      "2018-01-05      74.524237   3.900804   7.395659\n",
      "stoch_k_window          2                      \n",
      "stoch_d_window          3                      \n",
      "                        a          b          c\n",
      "2018-01-01            NaN        NaN        NaN\n",
      "2018-01-02            NaN        NaN        NaN\n",
      "2018-01-03            NaN        NaN        NaN\n",
      "2018-01-04      90.039421  12.025053  64.904657\n",
      "2018-01-05      84.869529   7.952381  35.000612\n"
     ]
    }
   ],
   "source": [
    "print(vbt.ta('StochasticOscillator').run(high=high['a'], low=low['a'], close=close['a'], window=2, smooth_window=3).stoch)\n",
    "print(vbt.ta('StochasticOscillator').run(high=high['a'], low=low['a'], close=close['a'], window=2, smooth_window=3).stoch_signal)\n",
    "print(vbt.talib('STOCHF').run(high, low, close, fastk_period=2, fastd_period=3).fastk)\n",
    "print(vbt.talib('STOCHF').run(high, low, close, fastk_period=2, fastd_period=3).fastd)\n",
    "print(vbt.STOCH.run(high, low, close, k_window=2, d_window=3).percent_k)\n",
    "print(vbt.STOCH.run(high, low, close, k_window=2, d_window=3).percent_d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "29.4 ms ± 199 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "26.6 ms ± 607 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "# One window\n",
    "%timeit vbt.talib('STOCHF').run(big_high, big_low, big_close, fastk_period=2)\n",
    "%timeit vbt.STOCH.run(big_high, big_low, big_close, k_window=2)\n",
    "\n",
    "print(vbt.STOCH.run(big_high, big_low, big_close, k_window=2).percent_d.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "220 ms ± 234 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "283 ms ± 5.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "(1000, 8000)\n"
     ]
    }
   ],
   "source": [
    "# Multiple windows\n",
    "%timeit vbt.talib('STOCHF').run(big_high, big_low, big_close, fastk_period=np.arange(2, 10))\n",
    "%timeit vbt.STOCH.run(big_high, big_low, big_close, k_window=np.arange(2, 10))\n",
    "\n",
    "print(vbt.STOCH.run(big_high, big_low, big_close, k_window=np.arange(2, 10)).percent_d.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "264 ms ± 672 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "132 ms ± 519 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 10000)\n"
     ]
    }
   ],
   "source": [
    "# One window repeated\n",
    "%timeit vbt.talib('STOCHF').run(big_high, big_low, big_close, fastk_period=np.full(10, 2))\n",
    "%timeit vbt.STOCH.run(big_high, big_low, big_close, k_window=np.full(10, 2))\n",
    "\n",
    "print(vbt.STOCH.run(big_high, big_low, big_close, k_window=np.full(10, 2)).percent_d.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "stoch_k_window          2                                4            \\\n",
      "stoch_d_window          2                                2             \n",
      "stoch_d_ewm         False                             True             \n",
      "                        a          b          c          a         b   \n",
      "2018-01-01            NaN        NaN        NaN        NaN       NaN   \n",
      "2018-01-02      90.033913  16.118819  97.107794        NaN       NaN   \n",
      "2018-01-03      98.459370  16.658503  85.664573        NaN       NaN   \n",
      "2018-01-04      81.624981   3.297837  11.941605  91.582811  1.221173   \n",
      "2018-01-05      74.524237   3.900804   7.395659  88.208468  1.313450   \n",
      "\n",
      "stoch_k_window             \n",
      "stoch_d_window             \n",
      "stoch_d_ewm                \n",
      "                        c  \n",
      "2018-01-01            NaN  \n",
      "2018-01-02            NaN  \n",
      "2018-01-03            NaN  \n",
      "2018-01-04      47.019332  \n",
      "2018-01-05       4.190157  \n",
      "stoch_k_window          2                                4            \\\n",
      "stoch_d_window          2                                2             \n",
      "stoch_d_ewm         False                             True             \n",
      "                        a          b          c          a         b   \n",
      "2018-01-01            NaN        NaN        NaN        NaN       NaN   \n",
      "2018-01-02            NaN        NaN        NaN        NaN       NaN   \n",
      "2018-01-03      94.246641  16.388661  91.386183        NaN       NaN   \n",
      "2018-01-04      90.042175   9.978170  48.803089        NaN       NaN   \n",
      "2018-01-05      78.074609   3.599321   9.668632  89.333249  1.282691   \n",
      "\n",
      "stoch_k_window             \n",
      "stoch_d_window             \n",
      "stoch_d_ewm                \n",
      "                        c  \n",
      "2018-01-01            NaN  \n",
      "2018-01-02            NaN  \n",
      "2018-01-03            NaN  \n",
      "2018-01-04            NaN  \n",
      "2018-01-05      18.466549  \n"
     ]
    }
   ],
   "source": [
    "stochastic = vbt.STOCH.run(high, low, close, k_window=[2, 4], d_window=2, d_ewm=[False, True])\n",
    "\n",
    "print(stochastic.percent_k)\n",
    "print(stochastic.percent_d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg class=\"main-svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"700\" height=\"350\" style=\"\" viewBox=\"0 0 700 350\"><rect x=\"0\" y=\"0\" width=\"700\" height=\"350\" style=\"fill: rgb(255, 255, 255); fill-opacity: 1;\"/><defs id=\"defs-634221\"><g class=\"clips\"><clipPath id=\"clip634221xyplot\" class=\"plotclip\"><rect width=\"634\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip634221x\"><rect x=\"36\" y=\"0\" width=\"634\" height=\"350\"/></clipPath><clipPath class=\"axesclip\" id=\"clip634221y\"><rect x=\"0\" y=\"46\" width=\"700\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip634221xy\"><rect x=\"36\" y=\"46\" width=\"634\" height=\"261\"/></clipPath></g><g class=\"gradients\"/></defs><g class=\"bglayer\"><rect class=\"bg\" x=\"36\" y=\"46\" width=\"634\" height=\"261\" style=\"fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;\"/></g><g class=\"layer-below\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"cartesianlayer\"><g class=\"subplot xy\"><g class=\"layer-subplot\"><g class=\"shapelayer\"><path data-index=\"0\" fill-rule=\"evenodd\" d=\"M71.45,223.95H634.55V129.05H71.45Z\" clip-path=\"url('#clip634221xy')\" style=\"opacity: 0.2; stroke: rgb(0, 0, 0); stroke-opacity: 0; fill: rgb(128, 0, 128); fill-opacity: 1; stroke-width: 0px;\"/></g><g class=\"imagelayer\"/></g><g class=\"gridlayer\"><g class=\"x\"><path class=\"xgrid crisp\" transform=\"translate(71.45,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(212.22,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(353,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(493.78,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(634.55,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g><g class=\"y\"><path class=\"ygrid crisp\" transform=\"translate(0,247.68)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,200.23)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,152.76999999999998)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,105.32)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,57.86)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g></g><g class=\"zerolinelayer\"><path class=\"yzl zl crisp\" transform=\"translate(0,295.14)\" d=\"M36,0h634\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 2px;\"/></g><path class=\"xlines-below\"/><path class=\"ylines-below\"/><g class=\"overlines-below\"/><g class=\"xaxislayer-below\"/><g class=\"yaxislayer-below\"/><g class=\"overaxes-below\"/><g class=\"plot\" transform=\"translate(36,46)\" clip-path=\"url('#clip634221xyplot')\"><g class=\"scatterlayer mlayer\"><g class=\"trace scatter tracee6e02416-9834-4208-b083-00165fbb94cd\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M176.22,35.51L317,15.52L457.78,55.46L598.55,72.31\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(176.22,35.51)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(317,15.52)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(457.78,55.46)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(598.55,72.31)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g><g class=\"text\"/></g><g class=\"trace scatter trace1d013e26-4c90-4c00-a091-b6deec38c2d5\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M317,25.51L457.78,35.49L598.55,63.89\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(255, 127, 14); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(317,25.51)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(457.78,35.49)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(598.55,63.89)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/></g><g class=\"text\"/></g></g></g><g class=\"overplot\"/><path class=\"xlines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><path class=\"ylines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><g class=\"overlines-above\"/><g class=\"xaxislayer-above\"><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(71.45,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\"><tspan class=\"line\" dy=\"0em\" x=\"0\" y=\"320\">Jan 1</tspan><tspan class=\"line\" dy=\"1.3em\" x=\"0\" y=\"320\">2018</tspan></text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(212.22,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 2</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(353,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 3</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(493.78,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 4</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(634.55,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 5</text></g></g><g class=\"yaxislayer-above\"><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,295.14)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,247.68)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">20</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,200.23)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">40</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,152.76999999999998)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">60</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,105.32)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">80</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"35\" y=\"4.199999999999999\" transform=\"translate(0,57.86)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">100</text></g></g><g class=\"overaxes-above\"/></g></g><g class=\"polarlayer\"/><g class=\"ternarylayer\"/><g class=\"geolayer\"/><g class=\"funnelarealayer\"/><g class=\"pielayer\"/><g class=\"treemaplayer\"/><g class=\"sunburstlayer\"/><g class=\"glimages\"/><defs id=\"topdefs-634221\"><g class=\"clips\"/><clipPath id=\"legend634221\"><rect width=\"134\" height=\"29\" x=\"0\" y=\"0\"/></clipPath></defs><g class=\"layer-above\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"infolayer\"><g class=\"legend\" pointer-events=\"all\" transform=\"translate(536,11.779999999999994)\"><rect class=\"bg\" shape-rendering=\"crispEdges\" style=\"stroke: rgb(68, 68, 68); stroke-opacity: 1; fill: rgb(255, 255, 255); fill-opacity: 1; stroke-width: 0px;\" width=\"134\" height=\"29\" x=\"0\" y=\"0\"/><g class=\"scrollbox\" transform=\"\" clip-path=\"url('#legend634221')\"><g class=\"groups\"><g class=\"traces\" transform=\"translate(0,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">%K</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"63.734375\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g><g class=\"traces\" transform=\"translate(66.234375,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">%D</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(255, 127, 14); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"64.671875\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g></g></g><rect class=\"scrollbar\" rx=\"20\" ry=\"3\" width=\"0\" height=\"0\" style=\"fill: rgb(128, 139, 164); fill-opacity: 1;\" x=\"0\" y=\"0\"/></g><g class=\"g-gtitle\"/><g class=\"g-xtitle\"/><g class=\"g-ytitle\"/></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "stochastic[(2, 2, False, 'a')].plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MACD"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01         NaN\n",
      "2018-01-02         NaN\n",
      "2018-01-03    0.305556\n",
      "2018-01-04    0.393519\n",
      "2018-01-05    0.443673\n",
      "Name: (3, 2, 2, a), dtype: float64\n",
      "2018-01-01         NaN\n",
      "2018-01-02         NaN\n",
      "2018-01-03         NaN\n",
      "2018-01-04    0.364198\n",
      "2018-01-05    0.417181\n",
      "Name: (3, 2, 2, a), dtype: float64\n",
      "2018-01-01         NaN\n",
      "2018-01-02         NaN\n",
      "2018-01-03         NaN\n",
      "2018-01-04    0.029321\n",
      "2018-01-05    0.026492\n",
      "Name: (3, 2, 2, a), dtype: float64\n",
      "macd_fastperiod      2               \n",
      "macd_slowperiod      3               \n",
      "macd_signalperiod    2               \n",
      "                     a    b         c\n",
      "2018-01-01         NaN  NaN       NaN\n",
      "2018-01-02         NaN  NaN       NaN\n",
      "2018-01-03         NaN  NaN       NaN\n",
      "2018-01-04         0.5 -0.5  0.166667\n",
      "2018-01-05         0.5 -0.5 -0.111111\n",
      "macd_fastperiod      2               \n",
      "macd_slowperiod      3               \n",
      "macd_signalperiod    2               \n",
      "                     a    b         c\n",
      "2018-01-01         NaN  NaN       NaN\n",
      "2018-01-02         NaN  NaN       NaN\n",
      "2018-01-03         NaN  NaN       NaN\n",
      "2018-01-04         0.5 -0.5  0.333333\n",
      "2018-01-05         0.5 -0.5  0.037037\n",
      "macd_fastperiod      2               \n",
      "macd_slowperiod      3               \n",
      "macd_signalperiod    2               \n",
      "                     a    b         c\n",
      "2018-01-01         NaN  NaN       NaN\n",
      "2018-01-02         NaN  NaN       NaN\n",
      "2018-01-03         NaN  NaN       NaN\n",
      "2018-01-04         0.0  0.0 -0.166667\n",
      "2018-01-05         0.0  0.0 -0.148148\n",
      "macd_fast_window           2                    \n",
      "macd_slow_window           3                    \n",
      "macd_signal_window         2                    \n",
      "macd_macd_ewm           True                    \n",
      "macd_signal_ewm         True                    \n",
      "                           a         b         c\n",
      "2018-01-01               NaN       NaN       NaN\n",
      "2018-01-02               NaN       NaN       NaN\n",
      "2018-01-03          0.305556 -0.305556  0.305556\n",
      "2018-01-04          0.393519 -0.393519  0.060185\n",
      "2018-01-05          0.443673 -0.443673 -0.167438\n",
      "macd_fast_window           2                    \n",
      "macd_slow_window           3                    \n",
      "macd_signal_window         2                    \n",
      "macd_macd_ewm           True                    \n",
      "macd_signal_ewm         True                    \n",
      "                           a         b         c\n",
      "2018-01-01               NaN       NaN       NaN\n",
      "2018-01-02               NaN       NaN       NaN\n",
      "2018-01-03               NaN       NaN       NaN\n",
      "2018-01-04          0.364198 -0.364198  0.141975\n",
      "2018-01-05          0.417181 -0.417181 -0.064300\n",
      "macd_fast_window           2                    \n",
      "macd_slow_window           3                    \n",
      "macd_signal_window         2                    \n",
      "macd_macd_ewm           True                    \n",
      "macd_signal_ewm         True                    \n",
      "                           a         b         c\n",
      "2018-01-01               NaN       NaN       NaN\n",
      "2018-01-02               NaN       NaN       NaN\n",
      "2018-01-03               NaN       NaN       NaN\n",
      "2018-01-04          0.029321 -0.029321 -0.081790\n",
      "2018-01-05          0.026492 -0.026492 -0.103138\n"
     ]
    }
   ],
   "source": [
    "print(vbt.ta('MACD').run(close['a'], window_fast=2, window_slow=3, window_sign=2).macd)\n",
    "print(vbt.ta('MACD').run(close['a'], window_fast=2, window_slow=3, window_sign=2).macd_signal)\n",
    "print(vbt.ta('MACD').run(close['a'], window_fast=2, window_slow=3, window_sign=2).macd_diff)\n",
    "\n",
    "print(vbt.talib('MACD').run(close, fastperiod=2, slowperiod=3, signalperiod=2).macd)  # uses sma\n",
    "print(vbt.talib('MACD').run(close, fastperiod=2, slowperiod=3, signalperiod=2).macdsignal)\n",
    "print(vbt.talib('MACD').run(close, fastperiod=2, slowperiod=3, signalperiod=2).macdhist)\n",
    "\n",
    "print(vbt.MACD.run(close, fast_window=2, slow_window=3, signal_window=2, macd_ewm=True, signal_ewm=True).macd)\n",
    "print(vbt.MACD.run(close, fast_window=2, slow_window=3, signal_window=2, macd_ewm=True, signal_ewm=True).signal)\n",
    "print(vbt.MACD.run(close, fast_window=2, slow_window=3, signal_window=2, macd_ewm=True, signal_ewm=True).hist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "28.4 ms ± 571 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "23.1 ms ± 969 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "# One window\n",
    "%timeit vbt.talib('MACD').run(big_close, fastperiod=2)\n",
    "%timeit vbt.MACD.run(big_close, fast_window=2)\n",
    "\n",
    "print(vbt.MACD.run(big_close, fast_window=2).macd.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "217 ms ± 2.93 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "145 ms ± 364 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 8000)\n"
     ]
    }
   ],
   "source": [
    "# Multiple windows\n",
    "%timeit vbt.talib('MACD').run(big_close, fastperiod=np.arange(2, 10))\n",
    "%timeit vbt.MACD.run(big_close, fast_window=np.arange(2, 10))\n",
    "\n",
    "print(vbt.MACD.run(big_close, fast_window=np.arange(2, 10)).macd.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "267 ms ± 1.33 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "134 ms ± 6.54 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 10000)\n"
     ]
    }
   ],
   "source": [
    "# One window repeated\n",
    "%timeit vbt.talib('MACD').run(big_close, fastperiod=np.full(10, 2))\n",
    "%timeit vbt.MACD.run(big_close, fast_window=np.full(10, 2))\n",
    "\n",
    "print(vbt.MACD.run(big_close, fast_window=np.full(10, 2)).macd.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "macd_fast_window           2                                                  \n",
      "macd_slow_window           3                                                  \n",
      "macd_signal_window         2                             3                    \n",
      "macd_macd_ewm           True                          True                    \n",
      "macd_signal_ewm         True                          True                    \n",
      "                           a         b         c         a         b         c\n",
      "2018-01-01               NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-02               NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-03          0.305556 -0.305556  0.305556  0.305556 -0.305556  0.305556\n",
      "2018-01-04          0.393519 -0.393519  0.060185  0.393519 -0.393519  0.060185\n",
      "2018-01-05          0.443673 -0.443673 -0.167438  0.443673 -0.443673 -0.167438\n",
      "macd_fast_window           2                                                  \n",
      "macd_slow_window           3                                                  \n",
      "macd_signal_window         2                             3                    \n",
      "macd_macd_ewm           True                          True                    \n",
      "macd_signal_ewm         True                          True                    \n",
      "                           a         b         c         a         b         c\n",
      "2018-01-01               NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-02               NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-03               NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-04          0.364198 -0.364198  0.141975       NaN       NaN       NaN\n",
      "2018-01-05          0.417181 -0.417181 -0.064300  0.396605 -0.396605  0.007716\n",
      "macd_fast_window           2                                                  \n",
      "macd_slow_window           3                                                  \n",
      "macd_signal_window         2                             3                    \n",
      "macd_macd_ewm           True                          True                    \n",
      "macd_signal_ewm         True                          True                    \n",
      "                           a         b         c         a         b         c\n",
      "2018-01-01               NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-02               NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-03               NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-04          0.029321 -0.029321 -0.081790       NaN       NaN       NaN\n",
      "2018-01-05          0.026492 -0.026492 -0.103138  0.047068 -0.047068 -0.175154\n"
     ]
    }
   ],
   "source": [
    "macd = vbt.MACD.run(close, fast_window=2, slow_window=3, signal_window=[2, 3], macd_ewm=True, signal_ewm=True)\n",
    "\n",
    "print(macd.macd)\n",
    "print(macd.signal)\n",
    "print(macd.hist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/indicators/basic.py:666: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in greater\n",
      "\n",
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/indicators/basic.py:667: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in greater\n",
      "\n",
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/indicators/basic.py:667: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in less_equal\n",
      "\n",
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/indicators/basic.py:668: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in less\n",
      "\n",
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/indicators/basic.py:669: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in less\n",
      "\n",
      "/Users/olegpolakow/Documents/SourceTree/vectorbt/vectorbt/indicators/basic.py:669: RuntimeWarning:\n",
      "\n",
      "invalid value encountered in greater_equal\n",
      "\n"
     ]
    },
    {
     "data": {
      "image/svg+xml": [
       "<svg class=\"main-svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"700\" height=\"350\" style=\"\" viewBox=\"0 0 700 350\"><rect x=\"0\" y=\"0\" width=\"700\" height=\"350\" style=\"fill: rgb(255, 255, 255); fill-opacity: 1;\"/><defs id=\"defs-bc22cb\"><g class=\"clips\"><clipPath id=\"clipbc22cbxyplot\" class=\"plotclip\"><rect width=\"637\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clipbc22cbx\"><rect x=\"33\" y=\"0\" width=\"637\" height=\"350\"/></clipPath><clipPath class=\"axesclip\" id=\"clipbc22cby\"><rect x=\"0\" y=\"46\" width=\"700\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clipbc22cbxy\"><rect x=\"33\" y=\"46\" width=\"637\" height=\"261\"/></clipPath></g><g class=\"gradients\"/></defs><g class=\"bglayer\"><rect class=\"bg\" x=\"33\" y=\"46\" width=\"637\" height=\"261\" style=\"fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;\"/></g><g class=\"layer-below\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"cartesianlayer\"><g class=\"subplot xy\"><g class=\"layer-subplot\"><g class=\"shapelayer\"/><g class=\"imagelayer\"/></g><g class=\"gridlayer\"><g class=\"x\"/><g class=\"y\"><path class=\"ygrid crisp\" transform=\"translate(0,251.96)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,196.92)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,141.88)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,86.84)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g></g><g class=\"zerolinelayer\"><path class=\"yzl zl crisp\" transform=\"translate(0,307)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 2px;\"/></g><path class=\"xlines-below\"/><path class=\"ylines-below\"/><g class=\"overlines-below\"/><g class=\"xaxislayer-below\"/><g class=\"yaxislayer-below\"/><g class=\"overaxes-below\"/><g class=\"plot\" transform=\"translate(33,46)\" clip-path=\"url('#clipbc22cbxyplot')\"><g class=\"barlayer mlayer\"><g class=\"trace bars\" shape-rendering=\"crispEdges\" style=\"opacity: 1;\"><g class=\"points\"><g class=\"point\"><path d=\"M0,0Z\" style=\"vector-effect: non-scaling-stroke; opacity: 1; stroke-width: 0px; fill: rgb(192, 192, 192); fill-opacity: 0.75;\"/></g><g class=\"point\"><path d=\"M0,0Z\" style=\"vector-effect: non-scaling-stroke; opacity: 1; stroke-width: 0px; fill: rgb(192, 192, 192); fill-opacity: 0.75;\"/></g><g class=\"point\"><path d=\"M0,0Z\" style=\"vector-effect: non-scaling-stroke; opacity: 1; stroke-width: 0px; fill: rgb(192, 192, 192); fill-opacity: 0.75;\"/></g><g class=\"point\"><path d=\"M382.2,261V244.86H509.6V261Z\" style=\"vector-effect: non-scaling-stroke; opacity: 1; stroke-width: 0px; fill: rgb(192, 192, 192); fill-opacity: 0.75;\"/></g><g class=\"point\"><path d=\"M509.6,261V246.42H637V261Z\" style=\"vector-effect: non-scaling-stroke; opacity: 1; stroke-width: 0px; fill: rgb(144, 238, 144); fill-opacity: 0.75;\"/></g></g></g></g><g class=\"scatterlayer mlayer\"><g class=\"trace scatter tracee7649fda-c5e5-4534-a359-84ddffd36824\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M318.5,92.82L445.9,44.41L573.3,16.8\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(318.5,92.82)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(445.9,44.41)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(573.3,16.8)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g><g class=\"text\"/></g><g class=\"trace scatter trace3a5199fe-b46e-433d-9f4d-6b2536443b1c\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M445.9,60.54L573.3,31.38\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(255, 127, 14); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(445.9,60.54)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(573.3,31.38)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/></g><g class=\"text\"/></g></g></g><g class=\"overplot\"/><path class=\"xlines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><path class=\"ylines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><g class=\"overlines-above\"/><g class=\"xaxislayer-above\"><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(96.7,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\"><tspan class=\"line\" dy=\"0em\" x=\"0\" y=\"320\">Jan 1</tspan><tspan class=\"line\" dy=\"1.3em\" x=\"0\" y=\"320\">2018</tspan></text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(224.1,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 2</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(351.5,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 3</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(478.9,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 4</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(606.3,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 5</text></g></g><g class=\"yaxislayer-above\"><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,307)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,251.96)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.1</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,196.92)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.2</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,141.88)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.3</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,86.84)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.4</text></g></g><g class=\"overaxes-above\"/></g></g><g class=\"polarlayer\"/><g class=\"ternarylayer\"/><g class=\"geolayer\"/><g class=\"funnelarealayer\"/><g class=\"pielayer\"/><g class=\"treemaplayer\"/><g class=\"sunburstlayer\"/><g class=\"glimages\"/><defs id=\"topdefs-bc22cb\"><g class=\"clips\"/><clipPath id=\"legendbc22cb\"><rect width=\"271\" height=\"29\" x=\"0\" y=\"0\"/></clipPath></defs><g class=\"layer-above\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"infolayer\"><g class=\"legend\" pointer-events=\"all\" transform=\"translate(399,11.779999999999994)\"><rect class=\"bg\" shape-rendering=\"crispEdges\" style=\"stroke: rgb(68, 68, 68); stroke-opacity: 1; fill: rgb(255, 255, 255); fill-opacity: 1; stroke-width: 0px;\" width=\"271\" height=\"29\" x=\"0\" y=\"0\"/><g class=\"scrollbox\" transform=\"\" clip-path=\"url('#legendbc22cb')\"><g class=\"groups\"><g class=\"traces\" transform=\"translate(0,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">MACD</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"78.453125\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g><g class=\"traces\" transform=\"translate(80.953125,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Signal</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(255, 127, 14); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"79.578125\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g><g class=\"traces\" transform=\"translate(163.03125,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Histogram</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"/><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"legendundefined\" d=\"M6,6H-6V-6H6Z\" transform=\"translate(20,0)\" style=\"stroke-width: 0px; fill: rgb(192, 192, 192); fill-opacity: 0.75;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"104.5625\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g></g></g><rect class=\"scrollbar\" rx=\"20\" ry=\"3\" width=\"0\" height=\"0\" style=\"fill: rgb(128, 139, 164); fill-opacity: 1;\" x=\"0\" y=\"0\"/></g><g class=\"g-gtitle\"/><g class=\"g-xtitle\"/><g class=\"g-ytitle\"/></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "macd[(2, 3, 2, True, True, 'a')].plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ATR"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01    0.000000\n",
      "2018-01-02    0.619423\n",
      "2018-01-03    0.818424\n",
      "2018-01-04    1.050826\n",
      "2018-01-05    1.233524\n",
      "Name: (2, a), dtype: float64\n",
      "2018-01-01    0.000000\n",
      "2018-01-02    1.053372\n",
      "2018-01-03    1.132864\n",
      "2018-01-04    1.087915\n",
      "2018-01-05    1.064337\n",
      "Name: (2, b), dtype: float64\n",
      "2018-01-01    0.000000\n",
      "2018-01-02    0.575961\n",
      "2018-01-03    0.878148\n",
      "2018-01-04    1.019107\n",
      "2018-01-05    1.057231\n",
      "Name: (2, c), dtype: float64\n",
      "atr_timeperiod         2                    \n",
      "                       a         b         c\n",
      "2018-01-01           NaN       NaN       NaN\n",
      "2018-01-02           NaN       NaN       NaN\n",
      "2018-01-03      1.068578  1.247932  1.105767\n",
      "2018-01-04      1.175904  1.145449  1.132916\n",
      "2018-01-05      1.296063  1.093104  1.114135\n",
      "atr_window         2                             3                    \n",
      "atr_ewm        False                          True                    \n",
      "                   a         b         c         a         b         c\n",
      "2018-01-01       NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-02  0.619423  1.053372  0.575961       NaN       NaN       NaN\n",
      "2018-01-03  1.068578  1.247932  1.105767  0.818424  1.132864  0.878148\n",
      "2018-01-04  1.150327  1.127661  1.170200  1.050826  1.087915  1.019107\n",
      "2018-01-05  1.349725  1.041862  1.127710  1.233524  1.064337  1.057231\n"
     ]
    }
   ],
   "source": [
    "print(vbt.ta('AverageTrueRange').run(high['a'], low['a'], close['a'], window=2).average_true_range)\n",
    "print(vbt.ta('AverageTrueRange').run(high['b'], low['b'], close['b'], window=2).average_true_range)\n",
    "print(vbt.ta('AverageTrueRange').run(high['c'], low['c'], close['c'], window=2).average_true_range)\n",
    "print(vbt.talib('ATR').run(high, low, close, timeperiod=2).real)\n",
    "print(vbt.ATR.run(high, low, close, window=[2, 3], ewm=[False, True]).atr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "22.5 ms ± 470 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "33.5 ms ± 340 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "# One window\n",
    "%timeit vbt.talib('ATR').run(big_high, big_low, big_close, timeperiod=2)\n",
    "%timeit vbt.ATR.run(big_high, big_low, big_close, window=2)\n",
    "\n",
    "print(vbt.ATR.run(big_high, big_low, big_close, window=2).atr.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "158 ms ± 695 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "110 ms ± 1.14 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 8000)\n"
     ]
    }
   ],
   "source": [
    "# Multiple windows\n",
    "%timeit vbt.talib('ATR').run(big_high, big_low, big_close, timeperiod=np.arange(2, 10))\n",
    "%timeit vbt.ATR.run(big_high, big_low, big_close, window=np.arange(2, 10)) # rolling min/max very expensive\n",
    "\n",
    "print(vbt.ATR.run(big_high, big_low, big_close, window=np.arange(2, 10)).atr.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "197 ms ± 1.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "67.5 ms ± 1.89 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
      "(1000, 10000)\n"
     ]
    }
   ],
   "source": [
    "# One window repeated\n",
    "%timeit vbt.talib('ATR').run(big_high, big_low, big_close, timeperiod=np.full(10, 2))\n",
    "%timeit vbt.ATR.run(big_high, big_low, big_close, window=np.full(10, 2))\n",
    "\n",
    "print(vbt.ATR.run(big_high, big_low, big_close, window=np.full(10, 2)).atr.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atr_window         2                             3                    \n",
      "atr_ewm        False                          True                    \n",
      "                   a         b         c         a         b         c\n",
      "2018-01-01  0.119114  0.823236  0.120724  0.119114  0.823236  0.120724\n",
      "2018-01-02  1.119732  1.283508  1.031199  1.119732  1.283508  1.031199\n",
      "2018-01-03  1.017425  1.212357  1.180335  1.017425  1.212357  1.180335\n",
      "2018-01-04  1.283229  1.042965  1.160065  1.283229  1.042965  1.160065\n",
      "2018-01-05  1.416221  1.040759  1.095355  1.416221  1.040759  1.095355\n",
      "atr_window         2                             3                    \n",
      "atr_ewm        False                          True                    \n",
      "                   a         b         c         a         b         c\n",
      "2018-01-01       NaN       NaN       NaN       NaN       NaN       NaN\n",
      "2018-01-02  0.619423  1.053372  0.575961       NaN       NaN       NaN\n",
      "2018-01-03  1.068578  1.247932  1.105767  0.818424  1.132864  0.878148\n",
      "2018-01-04  1.150327  1.127661  1.170200  1.050826  1.087915  1.019107\n",
      "2018-01-05  1.349725  1.041862  1.127710  1.233524  1.064337  1.057231\n"
     ]
    }
   ],
   "source": [
    "atr = vbt.ATR.run(high, low, close, window=[2, 3], ewm=[False, True])\n",
    "\n",
    "print(atr.tr)\n",
    "print(atr.atr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg class=\"main-svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"700\" height=\"350\" style=\"\" viewBox=\"0 0 700 350\"><rect x=\"0\" y=\"0\" width=\"700\" height=\"350\" style=\"fill: rgb(255, 255, 255); fill-opacity: 1;\"/><defs id=\"defs-4077c4\"><g class=\"clips\"><clipPath id=\"clip4077c4xyplot\" class=\"plotclip\"><rect width=\"637\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip4077c4x\"><rect x=\"33\" y=\"0\" width=\"637\" height=\"350\"/></clipPath><clipPath class=\"axesclip\" id=\"clip4077c4y\"><rect x=\"0\" y=\"46\" width=\"700\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip4077c4xy\"><rect x=\"33\" y=\"46\" width=\"637\" height=\"261\"/></clipPath></g><g class=\"gradients\"/></defs><g class=\"bglayer\"><rect class=\"bg\" x=\"33\" y=\"46\" width=\"637\" height=\"261\" style=\"fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;\"/></g><g class=\"layer-below\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"cartesianlayer\"><g class=\"subplot xy\"><g class=\"layer-subplot\"><g class=\"shapelayer\"/><g class=\"imagelayer\"/></g><g class=\"gridlayer\"><g class=\"x\"><path class=\"xgrid crisp\" transform=\"translate(68.6,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(210.05,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(351.5,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(492.95,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(634.4,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g><g class=\"y\"><path class=\"ygrid crisp\" transform=\"translate(0,276.02)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,240.96)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,205.89)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,170.82999999999998)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,135.76999999999998)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,100.71000000000001)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,65.64)\" d=\"M33,0h637\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g></g><g class=\"zerolinelayer\"/><path class=\"xlines-below\"/><path class=\"ylines-below\"/><g class=\"overlines-below\"/><g class=\"xaxislayer-below\"/><g class=\"yaxislayer-below\"/><g class=\"overaxes-below\"/><g class=\"plot\" transform=\"translate(33,46)\" clip-path=\"url('#clip4077c4xyplot')\"><g class=\"scatterlayer mlayer\"><g class=\"trace scatter trace56467a93-14a9-4806-8738-f507b3b93935\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M35.6,244.2L177.05,68.78L318.5,86.71L459.95,40.12L601.4,16.8\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(35.6,244.2)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(177.05,68.78)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(318.5,86.71)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(459.95,40.12)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(601.4,16.8)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g><g class=\"text\"/></g><g class=\"trace scatter traceeca4ae4c-4b8b-4418-9ecf-ee287672ac9f\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M177.05,156.49L318.5,77.75L459.95,63.41L601.4,28.46\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(255, 127, 14); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(177.05,156.49)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(318.5,77.75)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(459.95,63.41)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(601.4,28.46)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/></g><g class=\"text\"/></g></g></g><g class=\"overplot\"/><path class=\"xlines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><path class=\"ylines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><g class=\"overlines-above\"/><g class=\"xaxislayer-above\"><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(68.6,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\"><tspan class=\"line\" dy=\"0em\" x=\"0\" y=\"320\">Jan 1</tspan><tspan class=\"line\" dy=\"1.3em\" x=\"0\" y=\"320\">2018</tspan></text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(210.05,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 2</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(351.5,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 3</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(492.95,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 4</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(634.4,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 5</text></g></g><g class=\"yaxislayer-above\"><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,276.02)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.2</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,240.96)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.4</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,205.89)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.6</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,170.82999999999998)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">0.8</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,135.76999999999998)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">1</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,100.71000000000001)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">1.2</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"32\" y=\"4.199999999999999\" transform=\"translate(0,65.64)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">1.4</text></g></g><g class=\"overaxes-above\"/></g></g><g class=\"polarlayer\"/><g class=\"ternarylayer\"/><g class=\"geolayer\"/><g class=\"funnelarealayer\"/><g class=\"pielayer\"/><g class=\"treemaplayer\"/><g class=\"sunburstlayer\"/><g class=\"glimages\"/><defs id=\"topdefs-4077c4\"><g class=\"clips\"/><clipPath id=\"legend4077c4\"><rect width=\"130\" height=\"29\" x=\"0\" y=\"0\"/></clipPath></defs><g class=\"layer-above\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"infolayer\"><g class=\"legend\" pointer-events=\"all\" transform=\"translate(540,11.779999999999994)\"><rect class=\"bg\" shape-rendering=\"crispEdges\" style=\"stroke: rgb(68, 68, 68); stroke-opacity: 1; fill: rgb(255, 255, 255); fill-opacity: 1; stroke-width: 0px;\" width=\"130\" height=\"29\" x=\"0\" y=\"0\"/><g class=\"scrollbox\" transform=\"\" clip-path=\"url('#legend4077c4')\"><g class=\"groups\"><g class=\"traces\" transform=\"translate(0,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">TR</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"58.296875\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g><g class=\"traces\" transform=\"translate(60.796875,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">ATR</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(255, 127, 14); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(255, 127, 14); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"66.5\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g></g></g><rect class=\"scrollbar\" rx=\"20\" ry=\"3\" width=\"0\" height=\"0\" style=\"fill: rgb(128, 139, 164); fill-opacity: 1;\" x=\"0\" y=\"0\"/></g><g class=\"g-gtitle\"/><g class=\"g-xtitle\"/><g class=\"g-ytitle\"/></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "atr[(2, False, 'a')].plot().show_svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## OBV"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2018-01-01     3.0\n",
      "2018-01-02    12.0\n",
      "2018-01-03    16.0\n",
      "2018-01-04    25.0\n",
      "2018-01-05    29.0\n",
      "Name: a, dtype: float64\n",
      "2018-01-01     7.0\n",
      "2018-01-02     0.0\n",
      "2018-01-03    -9.0\n",
      "2018-01-04   -14.0\n",
      "2018-01-05   -21.0\n",
      "Name: b, dtype: float64\n",
      "2018-01-01    5.0\n",
      "2018-01-02    7.0\n",
      "2018-01-03    9.0\n",
      "2018-01-04    7.0\n",
      "2018-01-05   -1.0\n",
      "Name: c, dtype: float64\n",
      "               a     b    c\n",
      "2018-01-01   3.0   7.0  5.0\n",
      "2018-01-02  12.0   0.0  7.0\n",
      "2018-01-03  16.0  -9.0  9.0\n",
      "2018-01-04  25.0 -14.0  7.0\n",
      "2018-01-05  29.0 -21.0 -1.0\n",
      "               a     b    c\n",
      "2018-01-01   3.0   7.0  5.0\n",
      "2018-01-02  12.0   0.0  7.0\n",
      "2018-01-03  16.0  -9.0  9.0\n",
      "2018-01-04  25.0 -14.0  7.0\n",
      "2018-01-05  29.0 -21.0 -1.0\n"
     ]
    }
   ],
   "source": [
    "print(vbt.ta('OnBalanceVolumeIndicator').run(close['a'], volume['a']).on_balance_volume)\n",
    "print(vbt.ta('OnBalanceVolumeIndicator').run(close['b'], volume['b']).on_balance_volume)\n",
    "print(vbt.ta('OnBalanceVolumeIndicator').run(close['c'], volume['c']).on_balance_volume)\n",
    "print(vbt.talib('OBV').run(close, volume).real)\n",
    "print(vbt.OBV.run(close, volume).obv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "19.3 ms ± 549 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n",
      "17.1 ms ± 1.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
      "(1000, 1000)\n"
     ]
    }
   ],
   "source": [
    "%timeit vbt.talib('OBV').run(big_close, big_volume)\n",
    "%timeit vbt.OBV.run(big_close, big_volume)\n",
    "\n",
    "print(vbt.OBV.run(big_close, big_volume).obv.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "               a     b    c\n",
      "2018-01-01   3.0   7.0  5.0\n",
      "2018-01-02  12.0   0.0  7.0\n",
      "2018-01-03  16.0  -9.0  9.0\n",
      "2018-01-04  25.0 -14.0  7.0\n",
      "2018-01-05  29.0 -21.0 -1.0\n"
     ]
    }
   ],
   "source": [
    "obv = vbt.OBV.run(close, volume)\n",
    "\n",
    "print(obv.obv)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "obv_above      0                    5              \n",
      "               a      b      c      a      b      c\n",
      "2018-01-01  True   True   True  False   True  False\n",
      "2018-01-02  True  False   True   True  False   True\n",
      "2018-01-03  True  False   True   True  False   True\n",
      "2018-01-04  True  False   True   True  False   True\n",
      "2018-01-05  True  False  False   True  False  False\n"
     ]
    }
   ],
   "source": [
    "print(obv.obv_above([0, 5]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg class=\"main-svg\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"700\" height=\"350\" style=\"\" viewBox=\"0 0 700 350\"><rect x=\"0\" y=\"0\" width=\"700\" height=\"350\" style=\"fill: rgb(255, 255, 255); fill-opacity: 1;\"/><defs id=\"defs-00e0d4\"><g class=\"clips\"><clipPath id=\"clip00e0d4xyplot\" class=\"plotclip\"><rect width=\"640\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip00e0d4x\"><rect x=\"30\" y=\"0\" width=\"640\" height=\"350\"/></clipPath><clipPath class=\"axesclip\" id=\"clip00e0d4y\"><rect x=\"0\" y=\"46\" width=\"700\" height=\"261\"/></clipPath><clipPath class=\"axesclip\" id=\"clip00e0d4xy\"><rect x=\"30\" y=\"46\" width=\"640\" height=\"261\"/></clipPath></g><g class=\"gradients\"/></defs><g class=\"bglayer\"><rect class=\"bg\" x=\"30\" y=\"46\" width=\"640\" height=\"261\" style=\"fill: rgb(229, 236, 246); fill-opacity: 1; stroke-width: 0;\"/></g><g class=\"layer-below\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"cartesianlayer\"><g class=\"subplot xy\"><g class=\"layer-subplot\"><g class=\"shapelayer\"/><g class=\"imagelayer\"/></g><g class=\"gridlayer\"><g class=\"x\"><path class=\"xgrid crisp\" transform=\"translate(65.75,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(207.87,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(350,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(492.13,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"xgrid crisp\" transform=\"translate(634.25,0)\" d=\"M0,46v261\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g><g class=\"y\"><path class=\"ygrid crisp\" transform=\"translate(0,272.71000000000004)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,228.98)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,185.25)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,141.51999999999998)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,97.78)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/><path class=\"ygrid crisp\" transform=\"translate(0,54.05)\" d=\"M30,0h640\" style=\"stroke: rgb(255, 255, 255); stroke-opacity: 1; stroke-width: 1px;\"/></g></g><g class=\"zerolinelayer\"/><path class=\"xlines-below\"/><path class=\"ylines-below\"/><g class=\"overlines-below\"/><g class=\"xaxislayer-below\"/><g class=\"yaxislayer-below\"/><g class=\"overaxes-below\"/><g class=\"plot\" transform=\"translate(30,46)\" clip-path=\"url('#clip00e0d4xyplot')\"><g class=\"scatterlayer mlayer\"><g class=\"trace scatter trace32118ff4-e7a4-4e29-98a7-6c7e55a65fd7\" style=\"stroke-miterlimit: 2; opacity: 1;\"><g class=\"fills\"/><g class=\"errorbars\"/><g class=\"lines\"><path class=\"js-line\" d=\"M35.75,244.2L177.87,165.48L320,130.5L462.13,51.78L604.25,16.8\" style=\"vector-effect: non-scaling-stroke; fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px; opacity: 1;\"/></g><g class=\"points\"><path class=\"point\" transform=\"translate(35.75,244.2)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(177.87,165.48)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(320,130.5)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(462.13,51.78)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/><path class=\"point\" transform=\"translate(604.25,16.8)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g><g class=\"text\"/></g></g></g><g class=\"overplot\"/><path class=\"xlines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><path class=\"ylines-above crisp\" d=\"M0,0\" style=\"fill: none;\"/><g class=\"overlines-above\"/><g class=\"xaxislayer-above\"><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(65.75,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\"><tspan class=\"line\" dy=\"0em\" x=\"0\" y=\"320\">Jan 1</tspan><tspan class=\"line\" dy=\"1.3em\" x=\"0\" y=\"320\">2018</tspan></text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(207.87,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 2</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(350,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 3</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(492.13,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 4</text></g><g class=\"xtick\"><text text-anchor=\"middle\" x=\"0\" y=\"320\" transform=\"translate(634.25,0)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">Jan 5</text></g></g><g class=\"yaxislayer-above\"><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,272.71000000000004)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">5</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,228.98)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">10</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,185.25)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">15</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,141.51999999999998)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">20</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,97.78)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">25</text></g><g class=\"ytick\"><text text-anchor=\"end\" x=\"29\" y=\"4.199999999999999\" transform=\"translate(0,54.05)\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">30</text></g></g><g class=\"overaxes-above\"/></g></g><g class=\"polarlayer\"/><g class=\"ternarylayer\"/><g class=\"geolayer\"/><g class=\"funnelarealayer\"/><g class=\"pielayer\"/><g class=\"treemaplayer\"/><g class=\"sunburstlayer\"/><g class=\"glimages\"/><defs id=\"topdefs-00e0d4\"><g class=\"clips\"/><clipPath id=\"legend00e0d4\"><rect width=\"71\" height=\"29\" x=\"0\" y=\"0\"/></clipPath></defs><g class=\"layer-above\"><g class=\"imagelayer\"/><g class=\"shapelayer\"/></g><g class=\"infolayer\"><g class=\"legend\" pointer-events=\"all\" transform=\"translate(599,11.779999999999994)\"><rect class=\"bg\" shape-rendering=\"crispEdges\" style=\"stroke: rgb(68, 68, 68); stroke-opacity: 1; fill: rgb(255, 255, 255); fill-opacity: 1; stroke-width: 0px;\" width=\"71\" height=\"29\" x=\"0\" y=\"0\"/><g class=\"scrollbox\" transform=\"\" clip-path=\"url('#legend00e0d4')\"><g class=\"groups\"><g class=\"traces\" transform=\"translate(0,14.5)\" style=\"opacity: 1;\"><text class=\"legendtext\" text-anchor=\"start\" x=\"40\" y=\"4.680000000000001\" style=\"font-family: 'Open Sans', verdana, arial, sans-serif; font-size: 12px; fill: rgb(42, 63, 95); fill-opacity: 1; white-space: pre;\">OBV</text><g class=\"layers\" style=\"opacity: 1;\"><g class=\"legendfill\"/><g class=\"legendlines\"><path class=\"js-line\" d=\"M5,0h30\" style=\"fill: none; stroke: rgb(31, 119, 180); stroke-opacity: 1; stroke-width: 2px;\"/></g><g class=\"legendsymbols\"><g class=\"legendpoints\"><path class=\"scatterpts\" transform=\"translate(20,0)\" d=\"M3,0A3,3 0 1,1 0,-3A3,3 0 0,1 3,0Z\" style=\"opacity: 1; stroke-width: 0px; fill: rgb(31, 119, 180); fill-opacity: 1;\"/></g></g></g><rect class=\"legendtoggle\" x=\"0\" y=\"-9.5\" width=\"68.375\" height=\"19\" style=\"fill: rgb(0, 0, 0); fill-opacity: 0;\"/></g></g></g><rect class=\"scrollbar\" rx=\"20\" ry=\"3\" width=\"0\" height=\"0\" style=\"fill: rgb(128, 139, 164); fill-opacity: 1;\" x=\"0\" y=\"0\"/></g><g class=\"g-gtitle\"/><g class=\"g-xtitle\"/><g class=\"g-ytitle\"/></g></svg>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "obv['a'].plot().show_svg()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
